Uso de memoria de imagen de fondo de Android

El proyecto en el que estoy trabajando usa varios fondos de “alta resolución” (fíjate en las comillas). Para entrar en la situación, uno de ellos es un archivo PNG de 640×935 1.19M. Por lo que sé, incluso si Android descomprime imágenes en la memoria como datos sin procesar, esto debería ser:

640 x 935 x 4bytes = 2.39M

Tengo problemas de memoria en mi proyecto que realmente no puedo entender y espero que alguien pueda arrojar algo de luz sobre este asunto. Voy a nombrar dos dispositivos en los que estoy desarrollando y algunos de los resultados.

Para asegurarme de que esto no era un problema secundario, realicé una actividad para no cargar el fondo cuando se creó por primera vez y luego, cuando el usuario presiona un botón, todo lo que hace es:

findViewById(R.id.completed_block_background).setBackgroundResource(R.drawable.blockbackgroundbottom1); 

Luego, usando DDMS con “Update Heap” en el proceso (y primero forzando a GC a asegurarse de que esto no sea un problema), obtengo los siguientes resultados de memoria:

Nexus S: pasando de 18M a 26M (diferencia de 8M)

Galaxy Nexus: pasando de 28M a 39M (diferencia de 11M)

Entonces, como puede ver, poner esa imagen teóricamente sin comprimir de 2.39M en el fondo en realidad aumenta 8M y 11M en uso de memoria. ¿Alguien puede explicar por qué es esto y si hay alguna solución?

La única solución que he podido encontrar es el uso de mapas de bits para reducir a la mitad la resolución o reducir el formato del canal (hasta ahora esto es lo que hice, los cambié a 565 RGB, pero esto crea algunos problemas de bandas que no puedo aceptar).

También aceptaría, en caso de que no haya nada que se pueda hacer, una explicación de por qué sucede esto. Gracias por adelantado.

¿Es por eso que está haciendo que la imagen sea tan grande?

Bueno, lo que está sucediendo es que setBackgroundResource(R.drawable.blockbackgroundbottom1) va a hacer que Android primero haga lo de BitmapFactory.decodeResource() con el que experimentó, pero luego haga que la lógica de representación escale la imagen para aplicarla como fondo. Entonces, por ejemplo, la diferencia de 3MB entre Galaxy Nexus y Nexus S probablemente refleje la diferencia de tamaño, en píxeles, entre las representaciones de LinearLayout .

También puede haber algún remuestreo en función de la densidad de la pantalla, dependiendo de dónde haya almacenado esta imagen en el árbol de recursos.

¿Hay alguna manera de mantener el tamaño de la imagen original de alguna manera?

Por primera vez, primero trataría de ponerlo en res/drawable-nodpi/ (para evitar cualquier remuestreo automático basado en densidad), luego obtener manualmente el Bitmap través de la versión de BitmapFactory.decodeResource() que toma las BitmapFactory.Options , por lo que puede obtenerlo a medida que se lee. Si eso no parece ayudar mucho, es posible que tenga que mover el archivo PNG de los recursos dibujables a un recurso o recursos brutos, ya que Android podría intentar conservar un copia escalada de la imagen. No creo que lo haga si usa BitmapFactory.decodeResource() directamente usted mismo, pero no puedo descartarlo.