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.

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á utilizar MappedByteBuffer 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); 
  • Cargador universal de imágenes de Android que muestra parcialmente las imágenes
  • ImageView no estira la imagen correctamente
  • Fondo negro en la imagen cargada con univerisal cargador de imágenes
  • Cargador de imágenes universal: limpie el caché manualmente
  • Android - ImageLoader debe ser init con la configuración antes de usar en UIL
  • ImageView carga la imagen de alta resolución como muy mala calidad
  • ImageLoader - No descargues la imagen si ya está en caché
  • Cargador de imágenes universal dar imagen de error no se puede decodificar Android
  • UIL no admite esquema (protocolo) por defecto Debe implementar este soporte usted mismo
  • Android: cargador de imágenes universal cargar imagen grande
  • Universal Image Loader gridview parpadea después de la llamada notifyDataSetChanged
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.