Desarrollé una aplicación que usa muchas imágenes en Android.
La aplicación se ejecuta una vez, llena la información en la pantalla ( Layouts
, Listviews
, Textviews
, ImageViews
, etc) y el usuario lee la información.
No hay animación, ni efectos especiales ni nada que pueda llenar la memoria. A veces los elementos dibujables pueden cambiar. Algunos son recursos de Android y otros son archivos guardados en una carpeta en la SDCARD.
Luego, el usuario se cierra (el onDestroy
VM ejecuta el método y la aplicación permanece en la memoria) y luego, en algún momento, el usuario ingresa nuevamente.
Cada vez que el usuario ingresa a la aplicación, puedo ver que la memoria crece cada vez más hasta que el usuario obtiene la java.lang.OutOfMemoryError
.
Entonces, ¿cuál es la mejor / correcta forma de manejar muchas imágenes?
¿Debo ponerlos en métodos estáticos para que no se carguen todo el tiempo? ¿Tengo que limpiar el diseño o las imágenes utilizadas en el diseño de una manera especial?
fuente
Respuestas:
Parece que tienes una pérdida de memoria. El problema no es manejar muchas imágenes, es que sus imágenes no se desasignan cuando se destruye su actividad.
Es difícil decir por qué esto es sin mirar su código. Sin embargo, este artículo tiene algunos consejos que pueden ayudar:
http://android-developers.blogspot.de/2009/01/avoiding-memory-leaks.html
En particular, el uso de variables estáticas puede empeorar las cosas, no mejorarlas. Es posible que deba agregar un código que elimine las devoluciones de llamada cuando se redibuje su aplicación, pero nuevamente, aquí no hay suficiente información para asegurarlo.
fuente
Uno de los errores más comunes que encontré al desarrollar aplicaciones de Android es el error "java.lang.OutOfMemoryError: el tamaño del mapa de bits supera el presupuesto de VM". Encontré este error con frecuencia en actividades que utilizan muchos mapas de bits después de cambiar la orientación: la Actividad se destruye, se crea nuevamente y los diseños se "inflan" desde el XML que consume la memoria de VM disponible para mapas de bits.
El recolector de basura no asigna correctamente los mapas de bits en el diseño de la actividad anterior porque han cruzado referencias a su actividad. Después de muchos experimentos, encontré una solución bastante buena para este problema.
Primero, establezca el atributo "id" en la vista principal de su diseño XML:
Luego, en el
onDestroy()
método de su Actividad, llame alunbindDrawables()
método pasando una referencia a la Vista principal y luego haga unSystem.gc()
.Este
unbindDrawables()
método explora el árbol de vista de forma recursiva y:fuente
Para evitar este problema, puede utilizar el método nativo
Bitmap.recycle()
antesnull
-ingBitmap
objeto (o establecer otro valor). Ejemplo:Y luego puedes cambiar
myBitmap
sin llamarSystem.gc()
como:fuente
Me he encontrado con este problema exacto. El montón es bastante pequeño, por lo que estas imágenes pueden descontrolarse bastante rápido en lo que respecta a la memoria. Una forma es darle al recolector de basura una pista para recopilar memoria en un mapa de bits llamando a su método de reciclaje .
Además, no se garantiza que se llame al método onDestroy. Es posible que desee mover esta lógica / limpieza a la actividad onPause. Consulte el diagrama / tabla del ciclo de vida de la actividad en esta página para obtener más información.
fuente
onPause
sugerencia Estoy usando 4 pestañas conBitmap
imágenes en todas ellas, por lo que destruir la actividad podría no ocurrir demasiado pronto (si el usuario navega por todas las pestañas).Esta explicación podría ayudar: http://code.google.com/p/android/issues/detail?id=8488#c80
"Consejos rápidos:
1) NUNCA llame a System.gc () usted mismo. Esto se ha propagado como una solución aquí, y no funciona. No lo hagas. Si se dio cuenta en mi explicación, antes de obtener un OutOfMemoryError, la JVM ya ejecuta una recolección de basura, por lo que no hay razón para volver a hacerlo (está ralentizando su programa). Hacer uno al final de su actividad es solo encubrir el problema. Puede causar que el mapa de bits se coloque en la cola del finalizador más rápido, pero no hay ninguna razón por la que no podría haber llamado simplemente reciclar en cada mapa de bits.
2) Siempre llame a recycle () en mapas de bits que ya no necesita. Como mínimo, en onDestroy de su actividad, revise y recicle todos los mapas de bits que estaba utilizando. Además, si desea que las instancias de mapa de bits se recopilen del montón de dalvik más rápido, no está de más borrar cualquier referencia al mapa de bits.
3) Llamar a recycle () y luego System.gc () aún podría no eliminar el mapa de bits del montón de Dalvik. No se preocupe por esto. recycle () hizo su trabajo y liberó la memoria nativa, solo llevará algún tiempo seguir los pasos que describí anteriormente para eliminar realmente el mapa de bits del montón de Dalvik. ¡Esto NO es un gran problema porque la gran parte de la memoria nativa ya es gratuita!
4) Siempre asuma que hay un error en el marco pasado. Dalvik está haciendo exactamente lo que se supone que debe hacer. Puede que no sea lo que esperas o lo que quieres, pero es cómo funciona. "
fuente
Tuve exactamente el mismo problema. Después de algunas pruebas, descubrí que este error aparece para el escalado de imágenes grandes. Reduje la escala de la imagen y el problema desapareció.
PD: Al principio intenté reducir el tamaño de la imagen sin reducirla. Eso no detuvo el error.
fuente
Los siguientes puntos realmente me ayudaron mucho. Puede haber otros puntos también, pero estos son muy cruciales:
fuente
Sugiero una forma conveniente de resolver este problema. Simplemente asigne el valor del atributo "android: configChanges" como se sigue en Mainfest.xml para su actividad con errores. Me gusta esto:
La primera solución que ofrecí realmente había reducido la frecuencia de error OOM a un nivel bajo. Pero, no resolvió el problema totalmente. Y luego daré la segunda solución:
Como detalla la OOM, he usado demasiada memoria de tiempo de ejecución. Entonces, reduzco el tamaño de la imagen en ~ / res / drawable de mi proyecto. Tal como una imagen sobrecalificada que tiene una resolución de 128X128, podría redimensionarse a 64x64, lo que también sería adecuado para mi aplicación. Y después de hacerlo con un montón de imágenes, el error OOM no vuelve a ocurrir.
fuente
Yo también estoy frustrado por el error de memoria. Y sí, también descubrí que este error aparece mucho al escalar imágenes. Al principio intenté crear tamaños de imagen para todas las densidades, pero descubrí que esto aumentaba sustancialmente el tamaño de mi aplicación. Así que ahora solo estoy usando una imagen para todas las densidades y escalando mis imágenes.
Mi aplicación arrojaría un error de memoria cada vez que el usuario pasara de una actividad a otra. Establecer mis elementos dibujables en nulo y llamar a System.gc () no funcionó, ni reciclar mis bitmapDrawables con getBitMap (). Recycle (). Android continuaría arrojando el error de memoria con el primer enfoque, y lanzaría un mensaje de error de lienzo cada vez que intentara usar un mapa de bits reciclado con el segundo enfoque.
Adopté un tercer enfoque. Configuré todas las vistas como nulas y el fondo como negro. Hago esta limpieza en mi método onStop (). Este es el método que se llama tan pronto como la actividad ya no es visible. Si lo hace en el método onPause (), los usuarios verán un fondo negro. No es ideal. En cuanto a hacerlo en el método onDestroy (), no hay garantía de que se llame.
Para evitar que se produzca una pantalla negra si el usuario presiona el botón Atrás en el dispositivo, recargo la actividad en el método onRestart () llamando a los métodos startActivity (getIntent ()) y luego finish ().
Nota: no es realmente necesario cambiar el fondo a negro.
fuente
Los métodos BitmapFactory.decode *, discutidos en la lección Cargar mapas de bits grandes de manera eficiente , no deben ejecutarse en el hilo principal de la interfaz de usuario si los datos de origen se leen desde el disco o una ubicación de red (o realmente cualquier otra fuente que no sea memoria). El tiempo que tardan en cargar estos datos es impredecible y depende de una variedad de factores (velocidad de lectura desde el disco o la red, tamaño de la imagen, potencia de la CPU, etc.). Si una de estas tareas bloquea el hilo de la interfaz de usuario, el sistema marca su aplicación como no receptiva y el usuario tiene la opción de cerrarla (consulte Diseño de capacidad de respuesta para obtener más información).
fuente
Bueno, he intentado todo lo que encontré en Internet y ninguno de ellos funcionó. Llamar a System.gc () solo reduce la velocidad de la aplicación. Reciclar mapas de bits en onDestroy tampoco funcionó para mí.
Lo único que funciona ahora es tener una lista estática de todos los mapas de bits para que los mapas de bits sobrevivan después de un reinicio. Y solo use los mapas de bits guardados en lugar de crear nuevos cada vez que se reinicie la actividad.
En mi caso, el código se ve así:
fuente
Tuve el mismo problema solo con cambiar las imágenes de fondo con tamaños razonables. Obtuve mejores resultados al configurar ImageView en nulo antes de poner una nueva imagen.
fuente
FWIW, aquí hay un bitmap-cache ligero que codifiqué y he usado durante algunos meses. No son todas las campanas y silbatos, así que lea el código antes de usarlo.
fuente