Bitmap.copy () evita errores de memoria
Estoy usando universal-image-loader
biblioteca de universal-image-loader
para cargar imágenes, pero cuando llamo a copy()
en un archivo de mapa de bits cargado en algunos casos recibo OutOfMemoryError
. Aquí está mi código:
ImageLoader.getInstance().loadImage(path, new ImageLoadingListener() { @Override public void onLoadingStarted(String arg0, View arg1) { // TODO Auto-generated method stub } @Override public void onLoadingFailed(String arg0, View arg1, FailReason arg2) { // TODO Auto-generated method stub } @Override public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) { bm = arg2; } @Override public void onLoadingCancelled(String arg0, View arg1) { // TODO Auto-generated method stub } }); Bitmap bm2= bm.copy(Bitmap.Config.ARGB_8888, true); //where the crash happens
Necesito que el segundo Bitmap
no sea mutable, así que puedo dibujar sobre él.
- Carga perezosa de imágenes en ListView
- android: Universal Image Loader obtener dibujable de matriz de cadena
- ¿Puede Universal loader de imágenes para Android trabajar con imágenes de sqlite db?
- No se pudo encontrar la clase después de la actualización de android sdk 22
- La imagen no se muestra en ImageViewZoom
- URI de Universal Image Loader para Android desde InputStream
- Acceso a imágenes protegidas en el cargador de imágenes universal
- ¿Cómo cargar la miniatura con Universal Image Loader para Android?
- FileNotFoundException con Universal Image Loader
- ¿Cómo puedo cambiar el tamaño de una imagen antes de mostrarla en una vista con Android Universal Image Loader?
- ¿Es posible mostrar miniaturas de vídeo con Universal Image Loader y cómo?
- Universal Image Loader: ¿Puedo usar cache pero también actualizarlo?
- Combinación de CoverFlow y Universal Image Loader
En primer lugar, trate de encontrar un poco de tiempo para leer una buena documentación oficial sobre mapas de bits: Visualización eficiente de mapas de bits
Se le dará la comprensión de por qué y cuando java.lang.OutofMemoryError
sucede. Y cómo evitarlo.
¿Qué pasa con su pregunta: consulte este artículo: Android: convertir mapa de bits inmutable en mutable
Pero desde el nivel 11 de la API sólo
options.inMutable
disponible para cargar el archivo en un mapa de bits mutable.Por lo tanto, si estamos construyendo la aplicación con un nivel de API inferior a 11, entonces tenemos que encontrar algunas otras alternativas.
Una alternativa es crear otro mapa de bits copiando la fuente
bitmap. mBitmap = mBitmap.copy(ARGB_8888 ,true);
Pero lanzará
OutOfMemoryException
si el archivo de origen es grande. En realidad incase si queremos editar un archivo original, entonces enfrentaremos este problema. Debemos ser capaces de cargar al menos la imagen en la memoria, pero la mayoría no podemos asignar otra copia en la memoria.Por lo tanto, tenemos que guardar los bytes decodificados en algún lugar y borrar mapa de bits existente, a continuación, crear un nuevo mapa de bits mutable y volver a cargar los bytes guardados en mapa de bits de nuevo. Incluso para copiar bytes no podemos crear otro
ByteBuffer
dentro de la memoria. En ese caso, necesitará utilizarMappedByteBuffer
que asignará bytes dentro de un archivo de disco.El siguiente código explicaría claramente:
//this is the file going to use temporally to save the bytes. File file = new File("/mnt/sdcard/sample/temp.txt"); file.getParentFile().mkdirs(); //Open an RandomAccessFile /*Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" into AndroidManifest.xml file*/ RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); // get the width and height of the source bitmap. int width = bitmap.getWidth(); int height = bitmap.getHeight(); //Copy the byte to the file //Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888; FileChannel channel = randomAccessFile.getChannel(); MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, width*height*4); bitmap.copyPixelsToBuffer(map); //recycle the source bitmap, this will be no longer used. bitmap.recycle(); //Create a new bitmap to load the bitmap again. bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); map.position(0); //load it back from temporary bitmap.copyPixelsFromBuffer(map); //close the temporary file and channel , then delete that also channel.close(); randomAccessFile.close();
Y aquí está el código de ejemplo.
No se puede hacer mucho acerca del error de mapa de bits o de la memoria externa, excepto asegurarse de que el mapa de bits que está copiando o visualizando no es muy grande. Afortunadamente universal imageloader tiene una característica para comprimir mapa de bits mediante el cambio de la configuración. Así que pruebe Bitmap.Config.RGG_565. Se supone que la mitad de la huella de memoria del mapa de bits. También puede solicitar un tamaño de montón grande. Otra cosa que puedes hacer es copiar la versión escalada del mapa de bits.
Como Argumento Illegel dijo, es necesario asegurarse de que el mapa de bits no es demasiado grande. Además, asegúrese de que sólo está cargando un mapa de bits a la vez en la memoria.
Puede escalar dinámicamente el mapa de bits utilizando BitmapFactory
Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length) image.setImageBitmap(Bitmap.createScaledBitmap(b, 300, 300, false));
Agradezca que suceda en su dispositivo, y no sólo en los dispositivos de su usuario.
1) Eso es algo que tienes que hacer frente, y reaccionar adecuadamente. Mostrar mensaje de error o cargar una resolución inferior del mapa de bits. Su aplicación se ejecutará en muchos tipos de dispositivos, cada uno tiene una cantidad diferente de memoria.
2) Utilice la función importante Bitmap.recycle después de cada operación que hace su viejo mapa de bits redundante. Esto liberará inmediatamente la memoria para el siguiente trabajo sin esperar a que se ejecute el GC y posiblemente se produzcan errores de memoria.
Descargue este código del sitio
http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/
Extraer su ImageLoader, caché de archivos, las clases de caché de memoria utilizarlos en su mapa de bits para hacer cosas que no crean fuera de la excepción de memoria en absoluto y las imágenes de caché y aumentar el rendimiento
Utilice este Código para cumplir con su propósito
Hacer las siguientes clases en su código y en el último uso imageloader para cargar url pasar url, imageview y dibujable para mostrar incase url no está devolviendo ninguna imagen
FileCache.java
public class FileCache { private File cacheDir; public FileCache(Context context){ //Find the dir to save cached images if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"LazyList"); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); } public File getFile(String url){ //I identify images by hashcode. Not a perfect solution, good for the demo. String filename=String.valueOf(url.hashCode()); //Another possible solution (thanks to grantland) //String filename = URLEncoder.encode(url); File f = new File(cacheDir, filename); return f; } public void clear(){ File[] files=cacheDir.listFiles(); if(files==null) return; for(File f:files) f.delete(); } }
MemoryCache.java
public class MemoryCache { private Map<String, SoftReference<Bitmap>> cache=Collections.synchronizedMap(new HashMap<String, SoftReference<Bitmap>>()); public Bitmap get(String id){ if(!cache.containsKey(id)) return null; SoftReference<Bitmap> ref=cache.get(id); return ref.get(); } public void put(String id, Bitmap bitmap){ cache.put(id, new SoftReference<Bitmap>(bitmap)); } public void clear() { cache.clear(); } }
Utils.java
public class Utils { public static void CopyStream(InputStream is, OutputStream os) { final int buffer_size=1024; try { byte[] bytes=new byte[buffer_size]; for(;;) { int count=is.read(bytes, 0, buffer_size); if(count==-1) break; os.write(bytes, 0, count); } } catch(Exception ex){} } }
ImageLoader.java
public class ImageLoader { MemoryCache memoryCache=new MemoryCache(); FileCache fileCache; private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); ExecutorService executorService; public ImageLoader(Context context){ fileCache=new FileCache(context); executorService=Executors.newFixedThreadPool(5); } final int stub_id = R.drawable.no_image; public void DisplayImage(String url, ImageView imageView) { imageViews.put(imageView, url); Bitmap bitmap=memoryCache.get(url); if(bitmap!=null) imageView.setImageBitmap(bitmap); else { queuePhoto(url, imageView); imageView.setImageResource(stub_id); } } private void queuePhoto(String url, ImageView imageView) { PhotoToLoad p=new PhotoToLoad(url, imageView); executorService.submit(new PhotosLoader(p)); } private Bitmap getBitmap(String url) { File f=fileCache.getFile(url); //from SD cache Bitmap b = decodeFile(f); if(b!=null) return b; //from web try { Bitmap bitmap=null; URL imageUrl = new URL(url); HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection(); conn.setConnectTimeout(30000); conn.setReadTimeout(30000); conn.setInstanceFollowRedirects(true); InputStream is=conn.getInputStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); bitmap = decodeFile(f); return bitmap; } catch (Exception ex){ ex.printStackTrace(); return null; } } //decodes image and scales it to reduce memory consumption private Bitmap decodeFile(File f){ try { //decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //Find the correct scale value. It should be the power of 2. final int REQUIRED_SIZE=70; int width_tmp=o.outWidth, height_tmp=o.outHeight; int scale=1; while(true){ if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE) break; width_tmp/=2; height_tmp/=2; scale*=2; } //decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); } catch (FileNotFoundException e) {} return null; } //Task for the queue private class PhotoToLoad { public String url; public ImageView imageView; public PhotoToLoad(String u, ImageView i){ url=u; imageView=i; } } class PhotosLoader implements Runnable { PhotoToLoad photoToLoad; PhotosLoader(PhotoToLoad photoToLoad){ this.photoToLoad=photoToLoad; } @Override public void run() { if(imageViewReused(photoToLoad)) return; Bitmap bmp=getBitmap(photoToLoad.url); memoryCache.put(photoToLoad.url, bmp); if(imageViewReused(photoToLoad)) return; BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad); Activity a=(Activity)photoToLoad.imageView.getContext(); a.runOnUiThread(bd); } } boolean imageViewReused(PhotoToLoad photoToLoad){ String tag=imageViews.get(photoToLoad.imageView); if(tag==null || !tag.equals(photoToLoad.url)) return true; return false; } //Used to display bitmap in the UI thread class BitmapDisplayer implements Runnable { Bitmap bitmap; PhotoToLoad photoToLoad; public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;} public void run() { if(imageViewReused(photoToLoad)) return; if(bitmap!=null) photoToLoad.imageView.setImageBitmap(bitmap); else photoToLoad.imageView.setImageResource(stub_id); } } public void clearCache() { memoryCache.clear(); fileCache.clear(); } }
Llame a este código donde desee almacenar en caché o descargar o administrar imágenes
imageLoader.DisplayImage(song.get(CustomizedListView.KEY_THUMB_URL), thumb_image);
- ¿Creación de AlertDialog personalizado? ¿Qué es la vista de la raíz?
- ¿Cómo cambiar el nombre de la aplicación de Android y el ID de una aplicación existente?