2012-09-29 14 views
24

Estaría muy agradecido si alguien pudiera confirmar que he resuelto correctamente el siguiente problema o si hay una solución alternativa.Android error de carga de carga del mapa de bits Galaxy S3 WXGA

Tengo una aplicación que carga una imagen grande (por ejemplo, 800 * 1720 píxeles) en la memoria y la muestra en una vista de desplazamiento. La imagen es un plano de planta de un museo y quería un mapa simple como la experiencia de desplazamiento y zoom. La imagen cargó bien en dispositivos más antiguos, pero causó un error de falta de memoria en un Samsung Galaxy S3.

Al mirar los mensajes de LogCat resultó que al crear el mapa de bits se estaban asignando 22MB para el mapa de bits en lugar de 800 * 1720 * 4 = 5.5MB. Esencialmente se ha asignado la cantidad de memoria 4 veces requerida por otros dispositivos y empujando el uso de memoria sobre el tamaño de almacenamiento dinámico de 50MB.

La solución recomendada para este problema es utilizar la opción BitmapFactory.Options.inSampleSize para reducir la resolución de la imagen cargada y hacer que requiera menos memoria. Sin embargo, esto reduce la calidad de la imagen y, de hecho, quiero mostrarla en su tamaño original con la calidad original, ya que funciona bien en dispositivos más antiguos.

Después de mucho rascarse la cabeza, concluí que el problema era que la densidad de píxeles en las pantallas WXGA del S3 era 2.0 y por lo tanto para cada píxel en la imagen, el mapa de bits realmente estaba asignando 4 píxeles. Con un poco de ensayo y error descubrí que podía impedir que esto suceda mediante el establecimiento de options.inScaled = false;

http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html#inScaled

En el camino, también me di cuenta de que podía cortar el uso de memoria en medio de 2.7MB mediante el uso de una menor fidelidad profundidad de color de 2 píxeles en lugar de 4 píxeles configurando options.inPreferredConfig = Bitmap.Config.RGB_565;. Para mis pisos, esto no afectó la calidad de imagen visible.

El código final fue así:

String uri = "drawable/floorplan"; 
int imageResource = getResources().getIdentifier(uri, null, getPackageName()); 
BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inPreferredConfig = Bitmap.Config.RGB_565; 
options.inScaled = false; 
Bitmap bm = BitmapFactory.decodeResource(getResources(), imageResource, options); 
IVfloorplan.setImageBitmap(bm); 

Cuando se muestra este mapa de bits debe escalar una copia de seguridad. Para calcular el escalado se puede obtener la densidad de píxeles de:

float density = getResources().getDisplayMetrics().density; 

reduje uso de memoria para el mapa de bits de 22 MB a 2,7 MB, que en un montón de 50MB es significativo.

+3

Buen análisis y gracias por la solución. – Simon

+0

Creo que sería bueno proporcionar aquí el enlace de documentación que describe parcialmente lo mismo en inSampleSize: http://developer.android.com/training/displaying-bitmaps/load-bitmap.html. Y http://www.curious-creature.org/2010/12/08/bitmap-quality-banding-and-dithering/ sobre jugar con los formatos de color de mapa de bits y sus accesorios/contras. – sandrstar

+0

impresionante. Creo que esto ayudará incluso a otros dispositivos con menor tamaño de almacenamiento dinámico. Pero debe agregar una respuesta en lugar de responderla en su pregunta, ya que infringe las reglas de SO y hace que la pregunta no se elimine. –

Respuesta

2

La pantalla del S3 tiene una resolución muy alta, por lo que es bastante comprensible. Además, si la imagen está en la carpeta dibujable, podría obtener una escala adicional automáticamente. Puede haber formas de apagar eso. Incluso si el tamaño de su imagen no es casual, el sistema operativo tiene que asignar un búfer para acomodar la imagen, posiblemente también una para mostrarla en la pantalla.

Una alternativa es utilizar mosaico, que se utiliza en juegos como juegos SNES. Esta es también la forma en que manejaron muchos gráficos sin quedarse sin RAM. La evidencia muestra que así es como Google Maps tiene un mapa del planeta Tierra. Básicamente, corta la imagen grande en mosaicos y muestra los mosaicos en la pantalla mientras los enfocas (por supuesto, tal vez 1 loseta extra en cada lado).

Aunque esto es post-Honeycomb, donde Google puso el código para administrar mejor las asignaciones de Bitmap, tenga cuidado con la asignación de Bitmap. Se parece más a un programa C que a un programa Java, y es una buena idea administrarlo como tal. Es muy fácil quedarse sin espacio en el montón al usar objetos Bitmap en Android

Cuestiones relacionadas