2011-07-29 14 views
8

Creo que se preguntó y se preguntó antes, pero aún así, hay cosas que no puedo entender del todo.Almacenamiento en caché de imágenes de Android: ¿cómo?

He intentado dos enfoques diferentes:

  1. Mantenga todas las imágenes en la memoria, cuando se inicia cierto límite a superar, se inicia la eliminación de ellos
  2. Deje solución androide esto con SoftReferences

En 2. ¡simplemente los está limpiando a veces en el momento en que los asigno! Y no asigno demasiado: 30-40 imágenes 50x50 píxeles.

Así que me estoy quedando con uno. La pregunta es ¿cuál es el límite?

  1. ¿Puedo obtener información confiable del dispositivo de cuánta memoria de mapa de bits me queda exactamente? Investigué un poco, miro los valores de DDMS, solo estoy ocupando más y más espacio (si no limpio) hasta que explota. En un momento quedan solo 200K, luego el sistema proporciona 2M más ...
  2. Actualmente estoy usando alguna decisión heurística, basada en el modelo del dispositivo o el tamaño de la pantalla. Creo que esto es un callejón sin salida en el largo plazo. Obtuve excepciones de memoria en algunos teléfonos, completamente gratis en otros.
  3. ¿Existe una tercera solución, la correcta?
+0

Las imágenes de 30-40 del tamaño 50x50 no deben causar OOME. ¿Quizás cargue las más grandes? Si es así, puedes escalarlos. Además, si algunas imágenes se limpian de SoftReference, no se están utilizando, así que simplemente vuelva a cargarlas si es necesario. –

Respuesta

8

pregunta más importante: ¿Son usted recycle() -sus bitmaps? Esto es muy importante para las aplicaciones anteriores a Gingerbread (quizás también post-Gingerbread).

Ver el Memory Management for Android Apps session from Google I/O 2011 me ayudó a tener una mejor comprensión de las peculiaridades del desarrollo para Android.

Ese video menciona una herramienta llamada MAT - a Memory Analyzer - que es útil para determinar si tiene objetos perdidos en la memoria que se han filtrado. Es posible que tengas más de los 30-40 que crees que tienes.

Para ver y/o registrar el tamaño actual del montón, etc., sugiero usar el código en this answer about Android Out of Memory exceptions.

+0

Gracias por el enlace. He intentado reciclarlos, pero se usan en algunas vistas, y eso causa bloqueos cuando regreso a la actividad en la que se usan. – Danail

2

El límite está relacionado con el tamaño del montón VM en el dispositivo que está funcionando en, porque esta es diferente del dispositivo según el dispositivo y OS a OS que puede variar de 16 MB (total para la aplicación) a 256 MB + (en tabletas)

Deberá mantenerlo por debajo del extremo inferior, crear compilaciones diferentes por dispositivo o hacer que la aplicación verifique en tiempo de ejecución cuál es la asignación y cargue sus imágenes en consecuencia.

Existen métodos para el control de la cantidad de espacio libre en el montón y su tamaño:

Esta ref API le ayudará con los métodos avilable:

http://developer.android.com/reference/android/app/ActivityManager.html#getMemoryClass

+0

Hmm. ¿Qué se supone que debo usar allí? ¿MemoryInfo? Me parece algo restringido y ¿se trata del montón nativo? O el montón normal? Hasta ahora he usado Debug.getNativeHeapFreeSize(), pero no es confiable, le da el tamaño de límite máximo TEMPORAL, que puede elevarse más si la aplicación quiere más memoria de mapa de bits. – Danail

+0

No desea utilizar la información del montón nativo a menos que esté asignando de forma nativa de forma nativa con el NDK. La máquina virtual de Java tiene un tamaño de almacenamiento dinámico, algunas de las cuales pueden asignarse de forma nativa en determinadas llamadas de fábrica, como las de mapa de bits. Esto se deduce de su tamaño de Heap de VM asignado, aunque es nativo, por lo que si el Heap de VM es 16, puede asignar 4MB de forma nativa, entonces tendrá los 12 restantes en el Heap de VM. getMemoryClass() y getLargeMemoryClass() le darán la "clase" de montón VM permitida por el dispositivo en el que se está ejecutando. Este es el máximo que su aplicación podrá asignar. – Hamid

0

Desde una perspectiva de alto nivel, la carga de imágenes y el almacenamiento en caché es parte de GreenDroid framework. Echale un vistazo.

4

El almacenamiento en caché de imágenes fue una parte importante de una aplicación que he creado y puesto en la tienda de aplicaciones.La aplicación necesita descargar imágenes y almacenarlas en caché, tanto en la memoria como en la tarjeta SD, para que su alcance se extienda más allá de una sola ejecución.

La idea general fue agregar las imágenes a un Caching Manager que a) almacena la imagen en un contenedor asociativo (HashMap), a través de una clave basada en los metadatos, yb) escribe el archivo de imagen en el Tarjeta SD.

Durante condiciones de poca memoria, libero el HashMap. Sin embargo, las imágenes se pueden recuperar de la tarjeta SD_Card y una vez más la memoria caché.

Pude hacer esto sin reciclar y todavía no veo problemas de memoria. Según entiendo, el reciclaje no es necesario, pero ayuda a obtener una versión anterior de la memoria utilizada para "mapas de bits" debido al hecho de que la asignación para mapas de bits, en sistemas operativos anteriores a Gingerbread, usa memoria nativa. es decir, memoria que no es parte del montón de Dalvik. Entonces, el recolector de basura no libera esta memoria, sino que es liberada por políticas específicas de implementación.

Esto es de la clase Cache_Manager:

public static synchronized void addImage(Bitmap b, String urlString, boolean bSaveToFile, IMAGE_TYPES eIT, boolean bForce) 
{ 
    String szKey = getKeyFromUrlString(urlString, eIT); 

    if (false == m_hmCachedImages.containsKey(szKey) || bForce) 
    { 
     m_hmCachedImages.put(szKey, b); 
     if (bSaveToFile) 
     { 
      boolean bIsNull = false; 
      // Write a null object to disk to prevent future query for non-existent image. 
      if (null == b) 
      { 
       try 
       { 
        bIsNull = true; 
        b = getNullArt(); 
       } 
       catch (NullPointerException e) 
       { 
        e.printStackTrace(); 
        throw e; 
       } 
      } 

      // Don't force null art to disk 
      if (false == File_Manager.imageExists(szKey) || (bForce && bIsNull == false)) 
       File_Manager.writeImage(b, szKey); 
     } 
    } 
} 

// Aquí un ejemplo de writeImage() de la clase File_Manager

public static void writeImage(Bitmap bmp, String szFileName) 
{ 
    checkStorage(); 

    if (false == mExternalStorageWriteable) 
    { 
     Log.e("FileMan", "No Writable External Device Available"); 
     return; 
    } 

    try 
    { 
     // Create dirctory if doesn't exist 
     String szFilePath = getFilesPath(); 
     boolean exists = (new File(szFilePath)).exists(); 
     if (!exists) 
     { 
      new File(szFilePath).mkdirs(); 
     } 

     // Create file 
     File file = new File(szFilePath, szFileName); 

     // Write to file 
     FileOutputStream os = new FileOutputStream(file); 
     bmp.compress(Bitmap.CompressFormat.PNG, 90, os); 
    } catch (IOException e) 
    { 
     // Unable to create file, likely because 
     // external storage is 
     // not currently mounted. 
     Log.e("FileMan", "Error writing file", e); 
    } catch (Exception e) 
    { 
     e.printStackTrace(); 
     throw e; 
    } 
} 
+0

la situación conmigo es casi la misma, es posible que proporcione condiciones de poca memoria . Por supuesto, existe la posibilidad de que tenga pérdidas de memoria. – Danail

-2

Se puede usar un WebView para mostrar imágenes, que tiene el almacenamiento en caché incorporado. Además, admite zoom con 2 dedos y desplazamiento, sin ningún código especial.

Cuestiones relacionadas