我正在从Asset文件夹向数组对象加载100个图像。图片非常小(每个png~20k),我使用这个代码做,并防止内存泄漏&优化表现:
循环:
// create resized bitmap from asset resource
InputStream istr = assetManager.open(pics[i]);
Bitmap b = BitmapFactory.decodeStream(istr);
b = Bitmap.createScaledBitmap(b, 240, 240, true);
其中pics [i]是位于我的Asset文件夹中的文件名列表。
该代码适用于我,但我仍然不时收到用户的错误(我在Developer Console错误中看到它):
java.lang.OutOfMemoryError: bitmap size exceeds VM budget
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
我能做些什么来改善它吗?或者这是Android的世界,我们永远无法提供完美的应用程序?
答案 0 :(得分:2)
位图未压缩,因此它们以width * height * 4
字节存储。这意味着每个图像使用大约225 KB的内存。 100张图像需要大约22 MB的内存。最小堆大小为16 MB,但设备通常具有24+ MB堆。此堆不仅用于数据,还用于活动,视图等。这意味着您无法加载此大小的100位图。
答案 1 :(得分:2)
当然你可以改进一些东西:不要同时将太多的图片加载到内存中(或减小它们的大小)。有些设备没有太多可用内存。您的设备可能具有比某些客户电话更高的堆限制。因此,当它适合你时它会崩溃(请参阅this video了解一些堆限制[在4:44])。
您可以通过ActivityManager.getMemoryClass()
获得可用的堆大小。
要改善这一点,请立即测试您需要的图片(显示哪些图片),哪些不是。仅加载所需的位图并回收您不再需要的位图。
还可以尝试使用BitmapFactory.decodeResource()
和BitmapFactory.Options.inSampleSize
。这允许您直接以较低分辨率加载图像,而无需以完整尺寸加载它们,然后像在此处一样调整它们的大小。
答案 2 :(得分:1)
根据经验,您应该需要来显示用户实际可以看到的内容。在记忆中保存任何其他东西(图形)只是锦上添花。这就是为什么具有更高分辨率屏幕的设备将具有更大的堆大小。
例如,在320x480屏幕上,您只需要至少320x480x4 = 614400(600kb)。
考虑到这一概念,您需要考虑是否需要在内存中保留100 Bitmap
个。用户是否一次查看100 Bitmap
个?在这种情况下,您可以降低图像的质量而不会降低用户体验(屏幕上只有很多像素)。用户是否滚动了100 Bitmap
s?然后根据需要动态地转储和加载图像(通过一些缓存来获得平滑度)。
总有一种解决方法。