web-dev-qa-db-fra.com

Android utilisation de la mémoire de l'image d'arrière-plan

Le projet sur lequel je travaille utilise plusieurs arrière-plans "haute résolution" (notez les citations). Juste pour entrer dans la situation, l'un d'eux est un fichier PNG 640x935 1,19 M. Pour autant que je sache, même si Android décompresse les images en mémoire en tant que données brutes, cela devrait être:

640 x 935 x 4 octets = 2,39 M

J'ai des problèmes de mémoire sur mon projet que je ne peux pas vraiment comprendre et j'espère que quelqu'un pourra faire la lumière sur cette question. Je vais nommer deux appareils dans lesquels je développe et certains des résultats.

Pour m'assurer que ce n'était pas un problème secondaire, j'ai fait en sorte qu'une activité ne charge pas l'arrière-plan lors de sa création, puis, lorsque l'utilisateur appuie sur un bouton, il ne fait que:

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

Ensuite, en utilisant DDMS avec "Update Heap" sur le processus (et en forçant d'abord GC à s'assurer que ce ne sera pas un problème), j'obtiens les résultats de mémoire suivants:

Nexus S: passer de 18M à 26M (8M de différence)

Galaxy Nexus: passer de 28M à 39M (11M de différence)

Ainsi, comme vous pouvez le voir, le fait de mettre cette image non compressée théoriquement de 2,39 millions en arrière-plan augmente en fait de 8 à 11 millions d'utilisation de la mémoire. Quelqu'un peut-il expliquer pourquoi et s'il existe une solution?

La seule solution que j'ai pu trouver consiste à utiliser des bitmaps pour réduire de moitié la résolution ou pour réduire le format des canaux (jusqu'à présent, c'est ce que j'ai fait, je les ai passés à 565 RVB, mais cela pose des problèmes de bande que je ne peux pas accepter).

J'accepterais également, au cas où rien ne pourrait être fait, une explication de la raison pour laquelle cela se produit. Merci d'avance.

56
h4lc0n

Est-ce pourquoi cela rend l'image si grande?

Eh bien, ce qui se passe, c'est que setBackgroundResource(R.drawable.blockbackgroundbottom1) va provoquer Android pour faire d'abord la BitmapFactory.decodeResource() chose que vous avez expérimentée, mais ensuite avoir la logique de rendu redimensionner l'image pour l'appliquer comme arrière-plan. Ainsi, par exemple, la différence de 3 Mo entre le Galaxy Nexus et le Nexus S reflète probablement la différence de taille, en pixels, entre les rendus du LinearLayout.

Il peut également y avoir un rééchantillonnage en fonction de la densité de l'écran, selon l'endroit où vous avez stocké cette image dans votre arborescence de ressources.

Existe-t-il un moyen de lui faire conserver la taille de l'image d'origine de quelque façon?

Hors du brassard, j'essaierais d'abord de le mettre dans res/drawable-nodpi/ (Pour empêcher tout rééchantillonnage automatique basé sur la densité), puis d'obtenir manuellement le Bitmap via la version de BitmapFactory.decodeResource() qui prend le BitmapFactory.Options, afin que vous puissiez le faire évoluer au fur et à mesure qu'il est lu. Si cela ne semble pas beaucoup aider, vous devrez peut-être déplacer le PNG hors des ressources dessinables et vers une ressource ou des actifs bruts, comme Android pourrait toujours essayer de s'accrocher à une copie non mise à l'échelle de l'image. Je ne pense pas que ce sera le cas si vous utilisez BitmapFactory.decodeResource() directement vous-même, mais je ne peux pas statuer IT out.

111
CommonsWare