安卓背景图片内存使用

59
我正在从事的项目使用了几个“高分辨率”背景(注意引号)。其中之一是640x935 1.19M PNG文件。据我所知,即使Android将图像解压缩为原始数据存储在内存中,这也应该是:

640 x 935 x 4bytes = 2.39M

我的项目存在内存问题,但我无法真正理解它,希望有人能够解决这个问题。我将列举两个我正在开发的设备和一些结果。

为了确保这不是一个次要问题,我创建了一个活动,当它首次创建时不加载背景,然后当用户按下按钮时,它所做的就是:

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

然后,使用DDMS在进程上执行“更新堆”(并首先强制GC以确保这不会成为问题),我得到以下内存结果:

Nexus S:从18M增加到26M(差异为8M)

Galaxy Nexus:从28M增加到39M(差异为11M)

因此,正如您所看到的,将那个理论上未压缩的2.39M图像放入后台实际上会增加8M和11M的内存使用量。有人能解释一下为什么会这样,并且是否有任何解决方案吗?

我找到的唯一解决方案是使用位图减半分辨率或降低通道格式(到目前为止,这就是我所做的,将它们切换到565 RGB,但这会导致一些条纹问题,我无法接受)。

如果没有办法,我也会接受一个解释为什么会发生这种情况。提前感谢您。


你为什么认为你的1.19MB PNG文件只会占用2.12MB的堆空间?我预计它将占用更多的空间。 - CommonsWare
2
@CommonsWare他已经展示了计算过程:640 x 935 x 4bytes = 2.39M,你能发现他的错误吗? - lenik
@lenik:我从未见过压缩比如此糟糕的PNG。 - CommonsWare
@CommonsWare 我刚刚使用 BitmapFactory.decodeResource 创建了一个位图,getWidth() 和 getHeight() 分别返回 640 和 935。 - h4lc0n
@CommonsWare 哦,我现在明白你的意思了...不,绝对不是,那是一个跨越整个背景的线性布局。这就是为什么它会使图像变得如此大吗?有没有办法以任何方式保持原始图像大小? - h4lc0n
显示剩余3条评论
1个回答

117

这就是为什么图片会变得那么大的原因吗?

实际上,调用setBackgroundResource(R.drawable.blockbackgroundbottom1)会导致Android首先执行你尝试过的BitmapFactory.decodeResource(),然后通过渲染逻辑将图像缩放并应用为背景。例如,Galaxy Nexus和Nexus S之间的3MB差异可能反映了LinearLayout呈现方式中像素大小的差异。

根据此图像在资源树中的存储位置,还可能基于屏幕密度进行一些重新采样。

有没有办法保持原始图像的大小呢?

简单尝试的话,我建议首先将它放入res/drawable-nodpi/中(以防止任何自动基于密度的重新采样),然后通过带有BitmapFactory.Options参数的版本的BitmapFactory.decodeResource()方法手动获取Bitmap,这样可以在读取时按比例缩放。如果情况没有明显改善,您可能需要将PNG文件移出可绘制资源,并移入原始资源或资产目录,因为Android可能仍然会尝试保留未缩放的图像副本。如果直接使用BitmapFactory.decodeResource()自己的方法,则我认为不会出现这种情况,但是我不能排除此可能性。


13
太棒了...太棒了!你为我省去了很多麻烦。现在将图像移动到drawable-nodpi仅增加了大约1M的内存使用量...谢谢! - h4lc0n
4
如果您正在开发带有大量/众多图像的Android应用程序,那么这可能是我在SO上看到的最重要的内存管理快速修复提示。 - whyoz
1
有人能发布一下如何使用这种方法将图像设置为缩放背景的代码吗? - Mohamed Hafez
把图片放在res/drawable-nodpi而不是res/drawable里面就可以了吗? - Mohamed Hafez
2
回答了自己的问题,看起来确实是那么简单! - Mohamed Hafez
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接