我正在开发一个 Android 应用程序,它在其几个活动中使用多个大图像。每个图像大约为 1280x800,我为每个 Activity 加载大约 2-4 个这些图像。我意识到这些图像在分配给设备上每个单独应用程序的内存方面非常大,但是我怎样才能以原始分辨率显示它们而不会遇到 java.lang.OutOfMemory 错误?我需要这些图像在屏幕上以全尺寸显示(当屏幕小于图像时,xml 会自动进行缩放)。我看到了几种解决方案,涉及将图像缩小为缩略图并将其存储到内存中,但这不会导致图像失去其原始大小/分辨率吗?谢谢你的帮助!
3 回答
您可以对此做一些事情。
首先想到的是 1280x800(可能)是您的整个屏幕,因此您一次只需要显示一个。当你这样做时,不要记住其他人。
一个 1280x800 的图像,每像素 4 字节只有 4MB,而平板电脑现在似乎都提供了 48MB 的堆。如果需要,您应该能够在内存中保存一些。如果您的内存不足,则可能会泄漏。如果您在 DDMS 中观看,您的内存使用量是否会随着您更改活动而继续增长?
泄漏的常见来源是位图本身。完成后一定要打电话Bitmap#recycle
。
如果真的归结为它,并且您无法适应提供的堆空间,您也可以尝试android:largeHeap="true"
在清单中添加应用程序标签。这将要求系统为您提供更多堆空间 - 在某些设备上高达 256MB。不过,这应该是最后的手段,因为它会因设备而异,并且在某些设备上会被完全忽略(想到最初的 Kindle Fire)。
你可以看到你有多少总堆空间Runtime.getRuntime().maxMemory();
。有关更详细的说明,请参阅此答案。查看您正在使用多少会比较棘手,但是如果您想解决那个野兽,这里有一个描述。
最后,可能有比在 xml 中指定图像更好的方法来加载图像。请务必阅读此开发人员指南页面。即使您必须将它们保留在 xml 中,我也看到通过将图像资产拆分到drawable-hdpi
、drawable-mdpi
等目录而不是仅仅将它们转储到drawable
.
在使用 BitmapFactory 或相关方法加载图像之前,需要对图像进行缩放。
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
if (width > height) {
inSampleSize = Math.round((float)height / (float)reqHeight);
} else {
inSampleSize = Math.round((float)width / (float)reqWidth);
}
}
return inSampleSize;
}
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
whole thing is explained in Android developer site, Loading Large Bitmaps Efficiently