Android: Estrategia de caché de imágenes y tamaño de caché de memoria

Estoy implementando un sistema de caché de imágenes para almacenar en caché la imagen descargada.

Mi estrategia se basa en caché de dos niveles: Nivel de memoria y nivel de disco.

Mi clase es muy similar a la clase utilizada en el proyecto droidfu

Mis imágenes descargadas se ponen en un hashmap y el objeto Bitmap se envuelve dentro de un objeto SoftRererence. También cada imagen se guarda permanentemente en el disco. Si no se encuentra una imagen solicitada en Hashmap<String,SoftReference<Bitmap>> , se buscará en el disco, se leerá y volverá a insertarse en el hashmap. De lo contrario, la imagen se descargará de la red. Desde que almacenar las imágenes en el dispositivo phisical momery, he añadido un cheque para preservar el espacio del dispositivo y permanecer bajo un 1M de espacio ocupado:

 private void checkCacheUsage() { long size = 0; final File[] fileList = new File(mCacheDirPath).listFiles(); Arrays.sort(fileList, new Comparator<File>() { public int compare(File f1, File f2) { return Long.valueOf(f2.lastModified()).compareTo( f1.lastModified()); } }); for (File file : fileList) { size += file.length(); if (size > MAX_DISK_CACHE_SIZE) { file.delete(); Log.d(ImageCache.class.getSimpleName(), "checkCacheUsage: Size exceeded " + size + "(" + MAX_DISK_CACHE_SIZE + ") wiping older file {"+file.toString()+"}"); } } } 

Este método se llama en algún momento después de una escritura de disco:

 Random r = new Random(); int ra = r.nextInt(10); if (ra % 2 == 0){ checkCacheUsage(); } 

Lo que me gustaría añadir es la misma verificación en el tamaño HashMap para evitar que crezca demasiado. Algo como esto:

 private synchronized void checkMemoryCacheUsage(){ long size = 0; for (SoftReference<Bitmap> a : cache.values()) { final Bitmap b = a.get(); if (b != null && ! b.isRecycled()){ size += b.getRowBytes() * b.getHeight(); } if (size > MAX_MEMORY_SIZE){ //Remove some elements from the cache } } Log.d(ImageCache.class.getSimpleName(), "checkMemoryCacheUsage: " + size + " in memory"); } 

Mi pregunta es: ¿Qué podría ser un valor MAX_MEMORY_SIZE correcto? Además, ¿Es un buen enfoque? Una buena respuesta también podría ser: "¡No lo hagas! SoftReference ya es suficiente"

¡No lo hagas! SoftReference ya es suficiente! En realidad SoftReference está diseñado para hacer exactamente lo que necesita. A veces, SoftReference no hace lo que necesita. A continuación, acaba de deshacerse de SoftReference y escribir su propia lógica de gestión de memoria. Pero en la medida en que utilice SoftReference no debería preocuparse por el consumo de memoria, SoftReference lo hace por usted.

Estoy utilizando un tercio de la pila para el caché de la imagen.

 int memoryInMB = activityManager.getMemoryClass(); long totalAppHeap = memoryInMB * 1024 * 1024; int runtimeCacheLimit = (int)totalAppHeap/3; 

Por cierto, sobre la referencia suave, en Android Soft referencias no funcionan como esperas. Hay una cuestión de plataforma que las referencias suaves se recogen demasiado pronto, incluso cuando hay un montón de memoria libre.

Compruebe http://code-gotcha.blogspot.com/2011/09/softreference.html

He estado buscando en diferentes mecanismos de almacenamiento en caché para mi bitmaps a escala, memoria y ejemplos de caché de disco. Los ejemplos donde a complejo para mis necesidades, por lo que terminé haciendo mi propio caché de memoria de mapa de bits con LruCache. Puede ver un ejemplo de código de trabajo aquí o usar este código:

Memoria caché:

 public class Cache { private static LruCache<Integer, Bitmap> bitmaps = new BitmapLruCache(); public static Bitmap get(int drawableId){ Bitmap bitmap = bitmaps.get(drawableId); if(bitmap != null){ return bitmap; } else { bitmap = SpriteUtil.createScaledBitmap(drawableId); bitmaps.put(drawableId, bitmap); return bitmap; } } } 

BitmapLruCache:

 public class BitmapLruCache extends LruCache<Integer, Bitmap> { private final static int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); private final static int cacheSize = maxMemory / 2; public BitmapLruCache() { super(cacheSize); } @Override protected int sizeOf(Integer key, Bitmap bitmap) { // The cache size will be measured in kilobytes rather than number of items. return bitmap.getRowBytes() * bitmap.getHeight() / 1024; } } 
  • Cómo salir de error de memoria al iniciar una actividad en la aplicación android?
  • ¿El método ArrayList.clear () libera memoria?
  • Violación del número de instancias de la actividad StrictMode (2 instancias, 1 esperada) en la rotación de la actividad completamente vacía
  • Android: ¿Dónde está la herramienta Monitor de memoria?
  • Cómo borrar la memoria inactiva en Android mediante programación?
  • Gráficos Android gran consumo de memoria montón? - LibGDX
  • Android: Memory Analyzer eclipse plugin (1.1) no se inicia automáticamente al presionar ddms "hprof dump"
  • Android - MediaController pierde la actividad
  • Uso de memoria de Android AdMob
  • android R.integer devuelve incorrecto Valor extremadamente grande que causa fuera de mem mientras que crea el arsenal
  • Posible alternativa a las clases internas estáticas para evitar fugas de memoria en android / java?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.