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.
- Filtro de mercado para clase de memoria
- Pasar Contexto a ArrayAdapter dentro de Fragmento con setRetainInstance (true) causará la fuga?
- OnDraw eficiente con mapas de bits y aceleración por hardware
- ¿Qué significa si totalMemory es pequeño, pero totalPss es muy grande?
- Android: fugas de memoria al crear dinámicamente UI con fondos de recursos de imagen
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"
- El servidor NanoHttpd no puede transmitir videos grandes en android
- Android: liberación de la memoria asignada AnimationDrawable está utilizando hasta
- Android: Cannnot guardar datos downladed desde el servidor utilizando DownloadManager a la memoria interna
- Fugas de contexto de Android en AsyncTask
- ¿Hay de todos modos una aplicación puede utilizar más de 16mb en la memoria?
- Fragmentos retenidos con IU y fugas de memoria
- Android cómo implementar eficientemente el caché de datos y los eventos de cambio de configuración en fragmentos?
- Android NDK: Dalvik Heap y Native Heap - Cómo separar entre los dos
¡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; } }
- Token de acceso a Facebook siempre nulo
- En Android – ¿Cómo puedo registrar solo clics largos usando un ClickableSpan