Tengo una vista de lista con un par de botones de imagen en cada fila. Cuando hace clic en la fila de la lista, se inicia una nueva actividad. Tuve que crear mis propias pestañas debido a un problema con el diseño de la cámara. La actividad que se inicia para el resultado es un mapa. Si hago clic en mi botón para iniciar la vista previa de la imagen (cargar una imagen de la tarjeta SD), la aplicación vuelve de la actividad a la listview
actividad al controlador de resultados para relanzar mi nueva actividad, que no es más que un widget de imagen.
La vista previa de la imagen en la vista de lista se realiza con el cursor y ListAdapter
. Esto lo hace bastante simple, pero no estoy seguro de cómo puedo poner una imagen redimensionada (es decir, un tamaño de bit más pequeño, no un píxel, como el src
botón de imagen sobre la marcha. Así que simplemente cambié el tamaño de la imagen que salió de la cámara del teléfono.
El problema es que aparece un error de falta de memoria cuando intenta regresar y volver a iniciar la segunda actividad.
- ¿Hay alguna manera de construir el adaptador de lista fácilmente fila por fila, donde pueda cambiar el tamaño sobre la marcha (en cuanto a bits )?
Esto sería preferible ya que también necesito hacer algunos cambios en las propiedades de los widgets / elementos en cada fila ya que no puedo seleccionar una fila con la pantalla táctil debido al problema de enfoque. ( Puedo usar la bola del rodillo ) .
- Sé que puedo hacer un cambio de tamaño fuera de banda y guardar mi imagen, pero eso no es realmente lo que quiero hacer, pero algún código de muestra para eso sería bueno.
Tan pronto como desactivé la imagen en la vista de lista, funcionó bien nuevamente.
FYI: Así es como lo estaba haciendo:
String[] from = new String[] { DBHelper.KEY_BUSINESSNAME,DBHelper.KEY_ADDRESS,DBHelper.KEY_CITY,DBHelper.KEY_GPSLONG,DBHelper.KEY_GPSLAT,DBHelper.KEY_IMAGEFILENAME + ""};
int[] to = new int[] {R.id.businessname,R.id.address,R.id.city,R.id.gpslong,R.id.gpslat,R.id.imagefilename };
notes = new SimpleCursorAdapter(this, R.layout.notes_row, c, from, to);
setListAdapter(notes);
Donde R.id.imagefilename
esta a ButtonImage
.
Aquí está mi LogCat:
01-25 05:05:49.877: ERROR/dalvikvm-heap(3896): 6291456-byte external allocation too large for this process.
01-25 05:05:49.877: ERROR/(3896): VM wont let us allocate 6291456 bytes
01-25 05:05:49.877: ERROR/AndroidRuntime(3896): Uncaught handler: thread main exiting due to uncaught exception
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:304)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:149)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:174)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.graphics.drawable.Drawable.createFromPath(Drawable.java:729)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.resolveUri(ImageView.java:484)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ImageView.setImageURI(ImageView.java:281)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.setViewImage(SimpleCursorAdapter.java:183)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:129)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.CursorAdapter.getView(CursorAdapter.java:150)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.obtainView(AbsListView.java:1057)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.makeAndAddView(ListView.java:1616)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.fillSpecific(ListView.java:1177)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.ListView.layoutChildren(ListView.java:1454)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.AbsListView.onLayout(AbsListView.java:937)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutHorizontal(LinearLayout.java:1108)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:922)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1119)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.layoutVertical(LinearLayout.java:999)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.LinearLayout.onLayout(LinearLayout.java:920)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.widget.FrameLayout.onLayout(FrameLayout.java:294)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.View.layout(View.java:5611)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.performTraversals(ViewRoot.java:771)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.view.ViewRoot.handleMessage(ViewRoot.java:1103)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Handler.dispatchMessage(Handler.java:88)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.os.Looper.loop(Looper.java:123)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at android.app.ActivityThread.main(ActivityThread.java:3742)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invokeNative(Native Method)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at java.lang.reflect.Method.invoke(Method.java:515)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:739)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:497)
01-25 05:05:49.917: ERROR/AndroidRuntime(3896): at dalvik.system.NativeStart.main(Native Method)
01-25 05:10:01.127: ERROR/AndroidRuntime(3943): ERROR: thread attach failed
También tengo un nuevo error al mostrar una imagen:
01-25 22:13:18.594: DEBUG/skia(4204): xxxxxxxxxxx jpeg error 20 Improper call to JPEG library in state %d
01-25 22:13:18.604: INFO/System.out(4204): resolveUri failed on bad bitmap uri:
01-25 22:13:18.694: ERROR/dalvikvm-heap(4204): 6291456-byte external allocation too large for this process.
01-25 22:13:18.694: ERROR/(4204): VM won't let us allocate 6291456 bytes
01-25 22:13:18.694: DEBUG/skia(4204): xxxxxxxxxxxxxxxxxxxx allocPixelRef failed
fuente
Respuestas:
La clase de formación de Android , " Mostrar mapas de bits de manera eficiente ", ofrece información excelente para comprender y tratar la excepción
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
al cargar mapas de bits.Leer el mapa de bits Dimensiones y tipo
La
BitmapFactory
clase proporciona varios métodos de decodificación (decodeByteArray()
,decodeFile()
,decodeResource()
, etc.) para la creación de unaBitmap
de varias fuentes. Elija el método de decodificación más apropiado según su fuente de datos de imagen. Estos métodos intentan asignar memoria para el mapa de bits construido y, por lo tanto, pueden resultar fácilmente en unaOutOfMemory
excepción. Cada tipo de método de decodificación tiene firmas adicionales que le permiten especificar opciones de decodificación a través de laBitmapFactory.Options
clase. Ajuste de lainJustDecodeBounds
propiedad paratrue
al decodificar evita la asignación de memoria, volviendonull
para el objeto de mapa de bits, pero entornooutWidth
,outHeight
youtMimeType
. Esta técnica le permite leer las dimensiones y el tipo de los datos de la imagen antes de la construcción (y la asignación de memoria) del mapa de bits.Para evitar
java.lang.OutOfMemory
excepciones, verifique las dimensiones de un mapa de bits antes de decodificarlo, a menos que confíe absolutamente en la fuente para proporcionarle datos de imagen de tamaño predecible que se ajusten cómodamente a la memoria disponible.Cargue una versión reducida en la memoria
Ahora que se conocen las dimensiones de la imagen, se pueden usar para decidir si la imagen completa se debe cargar en la memoria o si se debe cargar una versión submuestreada. Aquí hay algunos factores a considerar:
Por ejemplo, no vale la pena cargar una imagen de 1024x768 píxeles en la memoria si eventualmente se mostrará en una miniatura de 128x96 píxeles en un
ImageView
.A decir que el decodificador submuestra de la imagen, la carga de una versión más pequeña en la memoria, juego
inSampleSize
atrue
en suBitmapFactory.Options
objeto. Por ejemplo, una imagen con resolución 2048x1536 que se decodifica con uninSampleSize
de 4 produce un mapa de bits de aproximadamente 512x384. Al cargar esto en la memoria se usan 0,75 MB en lugar de 12 MB para la imagen completa (suponiendo una configuración de mapa de bits deARGB_8888
). Aquí hay un método para calcular un valor de tamaño de muestra que es una potencia de dos en función del ancho y la altura del objetivo:Para usar este método, primero decodifique con
inJustDecodeBounds
set totrue
, pase las opciones y luego decodifique nuevamente usando el nuevoinSampleSize
valor yinJustDecodeBounds
configure enfalse
:Este método facilita la carga de un mapa de bits de tamaño arbitrariamente grande en un
ImageView
que muestra una miniatura de 100x100 píxeles, como se muestra en el siguiente código de ejemplo:Puede seguir un proceso similar para decodificar mapas de bits de otras fuentes, sustituyendo el
BitmapFactory.decode*
método apropiado según sea necesario.fuente
Para corregir el error OutOfMemory, debe hacer algo como esto:
Esta
inSampleSize
opción reduce el consumo de memoria.Aquí hay un método completo. Primero lee el tamaño de la imagen sin decodificar el contenido en sí. Luego encuentra el mejor
inSampleSize
valor, debe ser una potencia de 2, y finalmente la imagen se decodifica.fuente
He hecho una pequeña mejora en el código de Fedor. Básicamente hace lo mismo, pero sin el bucle while (en mi opinión) feo y siempre resulta en una potencia de dos. Felicitaciones a Fedor por hacer la solución original, me quedé atrapado hasta que encontré la suya, y luego pude hacer esta :)
fuente
BitmapFactory.decodeStream()
. ¿No tiene que guardar una referencia a cada uno de ellos para que puedan cerrarse en unfinally
bloque?Vengo de la experiencia de iOS y me sentí frustrado al descubrir un problema con algo tan básico como cargar y mostrar una imagen. Después de todo, todos los que tienen este problema están tratando de mostrar imágenes de tamaño razonable. De todos modos, aquí están los dos cambios que solucionaron mi problema (e hicieron que mi aplicación respondiera muy bien).
1) Cada vez que lo haga
BitmapFactory.decodeXYZ()
, asegúrese de pasar de unaBitmapFactory.Options
ainPurgeable
serie atrue
(y preferiblemente coninInputShareable
también establecer atrue
).2) NUNCA use
Bitmap.createBitmap(width, height, Config.ARGB_8888)
. Quiero decir NUNCA! Nunca he tenido esa cosa que no genera un error de memoria después de algunos pases. Ninguna cantidad derecycle()
,System.gc()
, lo ayudó. Siempre planteó excepciones. La otra forma en que realmente funciona es tener una imagen ficticia en sus elementos dibujables (u otro mapa de bits que decodificó usando el paso 1 anterior), cambiar el tamaño a lo que desee, luego manipular el mapa de bits resultante (como pasarlo a un lienzo para más diversión) Por lo tanto, lo que se debe usar en su lugar es:Bitmap.createScaledBitmap(srcBitmap, width, height, false)
. Si por alguna razón DEBE usar el método de creación de fuerza bruta, entonces al menos paseConfig.ARGB_4444
.Esto está casi garantizado para ahorrarle horas, si no días. Todo lo que se habla sobre escalar la imagen, etc., no funciona realmente (a menos que considere una solución para obtener un tamaño incorrecto o una imagen degradada).
fuente
BitmapFactory.Options options = new BitmapFactory.Options(); options.inPurgeable = true;
yBitmap.createScaledBitmap(srcBitmap, width, height, false);
resolvió mi problema que tenía con la excepción de memoria insuficiente en Android 4.0.0. ¡Gracias amigo!BitmapFactory.Options.inPurgeable
yBitmapFactory.Options.inInputShareable
están en desuso developer.android.com/reference/android/graphics/…Es un error conocido , no se debe a los archivos grandes. Como Android almacena en caché los Drawables, se está quedando sin memoria después de usar pocas imágenes. Pero he encontrado una forma alternativa de hacerlo, omitiendo el sistema de caché predeterminado de Android.
Solución : mueva las imágenes a la carpeta "activos" y use la siguiente función para obtener BitmapDrawable:
fuente
Tuve este mismo problema y lo resolví evitando las funciones BitmapFactory.decodeStream o decodeFile y en su lugar utilicé
BitmapFactory.decodeFileDescriptor
decodeFileDescriptor
parece que llama a métodos nativos diferentes que decodeStream / decodeFile.De todos modos, lo que funcionó fue esto (tenga en cuenta que agregué algunas opciones como algunas de las anteriores, pero eso no fue lo que marcó la diferencia. Lo que es crítico es la llamada a BitmapFactory.decodeFileDescriptor en lugar de decodeStream o decodeFile ):
Creo que hay un problema con la función nativa utilizada en decodeStream / decodeFile. He confirmado que se llama a un método nativo diferente cuando se usa decodeFileDescriptor. Además, lo que he leído es "que las imágenes (mapas de bits) no se asignan de una manera estándar de Java sino a través de llamadas nativas; las asignaciones se realizan fuera del montón virtual, ¡pero se cuentan en su contra! "
fuente
Creo que la mejor manera de evitarlo
OutOfMemoryError
es enfrentarlo y comprenderlo.Hice una aplicación para causar intencionalmente
OutOfMemoryError
y monitorear el uso de memoria.Después de hacer muchos experimentos con esta aplicación, tengo las siguientes conclusiones:
Voy a hablar sobre las versiones de SDK antes de Honey Comb primero.
El mapa de bits se almacena en el montón nativo, pero se recolectará basura automáticamente, no es necesario llamar a recycle ().
Si {Tamaño de almacenamiento dinámico de VM} + {memoria de almacenamiento dinámico nativa asignada}> = {Límite de tamaño de almacenamiento dinámico de VM para el dispositivo}, y está intentando crear un mapa de bits, se lanzará OOM.
AVISO: se cuenta el TAMAÑO DE HEAP DE VM en lugar de MEMORIA ASIGNADA DE VM.
El tamaño del montón de VM nunca se reducirá después de crecer, incluso si la memoria de VM asignada se reduce.
Por lo tanto, debe mantener la memoria máxima de la máquina virtual lo más baja posible para evitar que el tamaño de almacenamiento dinámico de la máquina virtual sea demasiado grande para guardar la memoria disponible para mapas de bits.
Llamar manualmente a System.gc () no tiene sentido, el sistema lo llamará primero antes de intentar aumentar el tamaño del almacenamiento dinámico.
El tamaño de almacenamiento dinámico nativo nunca se reducirá también, pero no se cuenta para OOM, por lo que no debe preocuparse.
Entonces, hablemos de SDK Starts de Honey Comb.
El mapa de bits se almacena en el montón de VM, la memoria nativa no se cuenta para OOM.
La condición para OOM es mucho más simple: {Tamaño de almacenamiento dinámico de VM}> = {Límite de tamaño de almacenamiento dinámico de VM para el dispositivo}.
Por lo tanto, tiene más memoria disponible para crear mapas de bits con el mismo límite de tamaño de almacenamiento dinámico, es menos probable que se genere OOM.
Estas son algunas de mis observaciones sobre la recolección de basura y la fuga de memoria.
Puede verlo usted mismo en la aplicación. Si una Actividad ejecutó una AsyncTask que todavía se estaba ejecutando después de que la Actividad fue destruida, la Actividad no obtendrá basura recolectada hasta que finalice AsyncTask.
Esto se debe a que AsyncTask es una instancia de una clase interna anónima, contiene una referencia de la Actividad.
Llamar a AsyncTask.cancel (verdadero) no detendrá la ejecución si la tarea se bloquea en una operación de E / S en el subproceso en segundo plano.
Las devoluciones de llamada son clases internas anónimas también, por lo que si una instancia estática en su proyecto las retiene y no las libera, se perderá memoria.
Si programó una tarea repetitiva o retrasada, por ejemplo, un temporizador, y no llama a cancel () y purge () en onPause (), se perderá memoria.
fuente
private static class
en la misma clase. No mantendrán ninguna referencia a la Actividad (a menos que les des una por supuesto)He visto muchas preguntas sobre excepciones OOM y almacenamiento en caché últimamente. La guía del desarrollador tiene un artículo realmente bueno sobre esto, pero algunos tienden a fallar al implementarlo de manera adecuada.
Debido a esto, escribí una aplicación de ejemplo que demuestra el almacenamiento en caché en un entorno Android. Esta implementación aún no ha recibido una OOM.
Mira al final de esta respuesta un enlace al código fuente.
Requisitos:
caracteristicas:
ListView
distancia, simplemente no va a descargar los mapas de bits entreEsto no incluye:
Código de muestra:
Las imágenes que se descargan son imágenes (75x75) de Flickr. Sin embargo, coloque las URL de imagen que desea procesar y la aplicación lo reducirá si excede el máximo. En esta aplicación, las URL están simplemente en una
String
matriz.El
LruCache
tiene una buena manera de hacer frente a los mapas de bits. Sin embargo, en esta aplicación puse una instancia de unaLruCache
clase de caché dentro de otra que creé para que la aplicación sea más factible.Cosas críticas de Cache.java (el
loadBitmap()
método es el más importante):No debería necesitar editar nada en el archivo Cache.java a menos que desee implementar el almacenamiento en caché de disco.
Cosas críticas de MainActivity.java:
getView()
se llama muy a menudo. Normalmente no es una buena idea descargar imágenes allí si no hemos implementado una verificación que nos asegure que no comenzaremos una cantidad infinita de hilos por fila. Cache.java comprueba si elrowObject.mBitmapUrl
ya está en una tarea y si lo está, no iniciará otra. Por lo tanto, lo más probable es que no excedamos la restricción de la cola de trabajo delAsyncTask
grupo.Descargar:
Puede descargar el código fuente desde https://www.dropbox.com/s/pvr9zyl811tfeem/ListViewImageCache.zip .
Ultimas palabras:
He probado esto durante algunas semanas, todavía no he recibido una sola excepción OOM. Probé esto en el emulador, en mi Nexus One y en mi Nexus S. Probé URL de imágenes que contenían imágenes en calidad HD. El único cuello de botella es que lleva más tiempo descargarlo.
Solo hay un escenario posible en el que puedo imaginar que aparecerá la OOM, y es que si descargamos muchas imágenes realmente grandes, y antes de que se escalen y se coloquen en caché, al mismo tiempo ocuparán más memoria y causarán una OOM. Pero esa ni siquiera es una situación ideal de todos modos y lo más probable es que no sea posible resolver de una manera más factible.
¡Informar errores en los comentarios! :-)
fuente
Hice lo siguiente para tomar la imagen y cambiar su tamaño sobre la marcha. Espero que esto ayude
fuente
Parece que este es un problema de larga duración, con muchas explicaciones diferentes. Tomé el consejo de las dos respuestas presentadas más comunes aquí, pero ninguna de ellas resolvió mis problemas de la VM afirmando que no podía permitirse los bytes para realizar la parte de decodificación del proceso. Después de investigar un poco, aprendí que el verdadero problema aquí es el proceso de decodificación que se lleva lejos del montón NATIVO .
Ver aquí: BitmapFactory OOM me vuelve loco
Eso me llevó a otro hilo de discusión donde encontré un par de soluciones más para este problema. Una es llamar
System.gc();
manualmente después de que se muestre su imagen. Pero eso realmente hace que su aplicación use MÁS memoria, en un esfuerzo por reducir el montón nativo. La mejor solución a partir del lanzamiento de 2.0 (Donut) es utilizar la opción BitmapFactory "inPurgeable". Entonces simplemente agreguéo2.inPurgeable=true;
justo despuéso2.inSampleSize=scale;
.Más sobre este tema aquí: ¿el límite de memoria es solo de 6M?
Ahora, habiendo dicho todo esto, también soy un completo tonto con Java y Android. Entonces, si cree que esta es una forma terrible de resolver este problema, probablemente tenga razón. ;-) Pero esto ha funcionado de maravilla para mí, y ahora me resulta imposible ejecutar la máquina virtual fuera de la memoria caché del montón. El único inconveniente que puedo encontrar es que estás destrozando tu imagen dibujada en caché. Lo que significa que si vuelves a la DERECHA de esa imagen, la estás redibujando cada vez. En el caso de cómo funciona mi aplicación, eso no es realmente un problema. Su experiencia puede ser diferente.
fuente
desafortunadamente si Ninguno de los anteriores funciona, entonces Agregue esto a su archivo de Manifiesto . Etiqueta de aplicación interna
fuente
Use esto
bitmap.recycle();
Esto ayuda sin ningún problema de calidad de imagen.fuente
Tengo una solución mucho más efectiva que no necesita escala de ningún tipo. Simplemente decodifique su mapa de bits solo una vez y luego almacénelo en un mapa con su nombre. Luego, simplemente recupere el mapa de bits con el nombre y configúrelo en ImageView. No hay nada más que deba hacerse.
Esto funcionará porque los datos binarios reales del mapa de bits decodificado no se almacenan en el montón de VM dalvik. Se almacena externamente. Por lo tanto, cada vez que decodifica un mapa de bits, asigna memoria fuera del montón de VM que nunca es reclamada por GC
Para ayudarlo a apreciar mejor esto, imagine que ha guardado su imagen en la carpeta dibujable. Simplemente obtienes la imagen haciendo getResources (). GetDrwable (R.drawable.). Esto NO decodificará su imagen cada vez, sino que reutilizará una instancia ya decodificada cada vez que la llame. Entonces, en esencia, está en caché.
Ahora, dado que su imagen está en un archivo en algún lugar (o incluso puede provenir de un servidor externo), es SU responsabilidad almacenar en caché la instancia de mapa de bits decodificada para reutilizarla donde sea necesario.
Espero que esto ayude.
fuente
He resuelto el mismo problema de la siguiente manera.
fuente
Hay dos problemas aquí....
fuente
¡Esto funcionó para mí!
fuente
Ninguna de las respuestas anteriores funcionó para mí, pero se me ocurrió una solución horriblemente fea que resolvió el problema. Agregué una imagen muy pequeña de 1x1 píxeles a mi proyecto como recurso, y la cargué en mi ImageView antes de llamar a la recolección de basura. Creo que podría ser que ImageView no lanzara el mapa de bits, por lo que GC nunca lo recogió. Es feo, pero parece estar funcionando por ahora.
fuente
bitmap
en el código anterior está la imagen ya mostrada anteriormente, debes reciclar eso, borrar cualquier referencia a él,imageView
olvidarlo también configurando un pequeño reemplazogc()
; y después de todo esto: cargue su NUEVA imagenbitmap
y muéstrela...
en el código anterior.Grandes respuestas aquí, pero quería una clase completamente utilizable para abordar este problema ... así que hice una.
Aquí está mi clase BitmapHelper que es a prueba de OutOfMemoryError :-)
fuente
Esto funciona para mi.
y esto está en C # monodroid. puedes cambiar fácilmente la ruta de la imagen. Lo importante aquí son las opciones a configurar.
fuente
Este parece ser el lugar apropiado para compartir mi clase de utilidad para cargar y procesar imágenes con la comunidad, puede usarlo y modificarlo libremente.
fuente
En una de mis aplicaciones, necesito tomar una foto
Camera/Gallery
. Si el usuario hace clic en la imagen de la cámara (puede ser 2MP, 5MP u 8MP), el tamaño de la imagen varía dekB
saMB
s. Si el tamaño de la imagen es menor (o hasta 1-2 MB) por encima del código funciona bien, pero si tengo una imagen de tamaño superior a 4 MB o 5 MB, entoncesOOM
aparece en el cuadro :(luego he trabajado para resolver este problema y finalmente he realizado la siguiente mejora en el código de Fedor (All Credit to Fedor por hacer una solución tan agradable) :)
¡Espero que esto ayude a los amigos que enfrentan el mismo problema!
Para más información, consulte esto
fuente
Me encontré con este problema hace un par de minutos. Lo resolví haciendo un mejor trabajo en la administración de mi adaptador listview. Pensé que era un problema con los cientos de imágenes de 50x50px que estaba usando, resultó que estaba tratando de inflar mi vista personalizada cada vez que se mostraba la fila. Simplemente probando para ver si la fila se había inflado, eliminé este error y estoy usando cientos de mapas de bits. Esto es en realidad para un Spinner, pero el adaptador base funciona igual para un ListView. Esta solución simple también mejoró en gran medida el rendimiento del adaptador.
fuente
He pasado todo el día probando estas soluciones y lo único que funcionó para mí es los enfoques anteriores para obtener la imagen y llamar manualmente al GC, que sé que no se supone que sea necesario, pero es lo único que funcionó cuando pongo mi aplicación bajo pruebas de carga pesada cambiando entre actividades. Mi aplicación tiene una lista de imágenes en miniatura en una vista de lista en (digamos actividad A) y cuando hace clic en una de esas imágenes lo lleva a otra actividad (digamos actividad B) que muestra una imagen principal para ese elemento. Cuando cambiaba entre las dos actividades, eventualmente recibía el error OOM y la aplicación se cerraba.
Cuando llegaba a la mitad de la vista de lista, se bloqueaba.
Ahora, cuando implemente lo siguiente en la actividad B, puedo revisar toda la vista de lista sin ningún problema y seguir y seguir y seguir ... y es bastante rápido.
fuente
Este problema solo ocurre en los emuladores de Android. También enfrenté este problema en un emulador, pero cuando registré un dispositivo, funcionó bien.
Así que por favor verifique un dispositivo. Se puede ejecutar en el dispositivo.
fuente
Mis 2 centavos: resolví mis errores de OOM con mapas de bits de la siguiente manera:
a) escalar mis imágenes por un factor de 2
b) usar la biblioteca Picasso en mi Adaptador personalizado para ListView, con una llamada en getView como esta:
Picasso.with(context).load(R.id.myImage).into(R.id.myImageView);
fuente
use este código para cada imagen en select de SdCard o dibujable para convertir objetos de mapa de bits.
use la ruta de su imagen en ImageData_Path.get (img_pos) .getPath () .
fuente
En general, el tamaño de almacenamiento dinámico del dispositivo Android es de solo 16 MB (varía según el dispositivo / sistema operativo, vea los tamaños de almacenamiento dinámico posteriores ), si está cargando las imágenes y cruza el tamaño de 16 MB, se saldrá de la memoria, en lugar de usar el mapa de bits para cargar las imágenes de la tarjeta SD o de los recursos o incluso de la red intentan usar getImageUri , cargar el mapa de bits requiere más memoria, o puede establecer el mapa de bits en nulo si su trabajo se realizó con ese mapa de bits.
fuente
Todas las soluciones aquí requieren establecer un IMAGE_MAX_SIZE. Esto limita los dispositivos con hardware más potente y si el tamaño de la imagen es demasiado bajo, se ve feo en la pantalla HD.
Salí con una solución que funciona con mi Samsung Galaxy S3 y varios otros dispositivos, incluidos los menos potentes, con una mejor calidad de imagen cuando se usa un dispositivo más potente.
La esencia de esto es calcular la memoria máxima asignada para la aplicación en un dispositivo en particular, luego configurar la escala para que sea lo más baja posible sin exceder esta memoria. Aquí está el código:
Establecí la memoria máxima utilizada por este mapa de bits como el 25% de la memoria máxima asignada, es posible que deba ajustar esto a sus necesidades y asegurarse de que este mapa de bits esté limpio y no permanezca en la memoria cuando haya terminado de usarlo. Por lo general, uso este código para realizar la rotación de la imagen (mapa de bits de origen y de destino), por lo que mi aplicación necesita cargar 2 mapas de bits en la memoria al mismo tiempo, y el 25% me da un buen búfer sin quedarse sin memoria al realizar la rotación de la imagen.
Espero que esto ayude a alguien por ahí ...
fuente
Esto
OutofMemoryException
no puede resolverse totalmente llamando alSystem.gc()
y así sucesivamente.Al referirse al ciclo de vida de la actividadLos estados de actividad están determinados por el propio sistema operativo sujeto al uso de memoria para cada proceso y la prioridad de cada proceso.
Puede considerar el tamaño y la resolución de cada una de las imágenes de mapa de bits utilizadas. Recomiendo reducir el tamaño, volver a muestrear a una resolución más baja, consultar el diseño de las galerías (una imagen pequeña PNG y una imagen original).
fuente
Este código ayudará a cargar mapas de bits grandes desde dibujables
fuente
Bitmap.Config.ARGB_565
? Si la alta calidad no es crítica.