具有大型高分辨率图像的java.lang.OutOfMemory

时间:2013-01-09 16:55:22

标签: android memory bitmap imageview allocation

我正在开发一款Android应用,它在其多项活动中使用了多个大图像。每张图片大约为1280x800,我为每个活动加载了大约2-4张这些图片。我意识到这些图像在分配给设备上的每个应用程序的内存方面非常大,但是如何以原始分辨率显示它们而不会遇到java.lang.OutOfMemory错误?我需要在屏幕上以完整尺寸显示这些图像(当屏幕小于图像时,缩放由xml自动完成)。我看到了几个解决方案,包括将图像缩小到缩略图并将其存储到内存中,但这不会导致图像丢失原始大小/分辨率吗?谢谢你的帮助!

3 个答案:

答案 0 :(得分:3)

您可以采取一些措施。

首先想到的是1280x800(可能)是您的整个屏幕,所以您只需要一次显示一个。当你这样做时,不要把其他人留在记忆中。

仍然是每像素4个字节的1280x800图像只有4MB,平板电脑似乎都提供了48MB的堆。如果需要,你应该能够在记忆中保留一些。如果你的内存不足,你可能会泄漏。如果您在DDMS中观看,在更改活动时您的内存使用量是否会继续增长?

泄漏的常见原因是位图本身。完成后请务必致电Bitmap#recycle

如果确实归结为它,并且您无法适应所提供的堆空间,您还可以尝试将android:largeHeap="true"添加到清单中的应用程序标记。这将要求系统为您提供更多的堆空间 - 在某些设备上最多可达256MB。这应该是最后的手段,因为它会因设备而异,并且在某些设备上完全被忽略(原来的Kindle Fire会浮现在脑海中)。

您可以看到Runtime.getRuntime().maxMemory();的总堆空间大小。有关更详细的说明,请参阅this answer。看看你使用了多少是很棘手的,但是如果你想要解决这个野兽的问题就有一个描述here

最后,加载图像可能比在xml中指定它们更好。请务必阅读此developer guide page。即使你必须将它们保留在xml中,我已经看到通过将图像资源分成drawable-hdpidrawable-mdpi等目录而不是仅仅将它们转储到drawable中,显着改善了内存使用情况。

答案 1 :(得分:1)

This article很好地描述了如何使用Eclipse MAT创建堆转储并对其进行分析。这将帮助您很快找到最可能发生内存泄漏的嫌疑人。

我再次指出this great link我从另一个SO问题中找到了有关如何正确解决问题的教程。

答案 2 :(得分:0)

在使用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);
}

Android开发者网站Loading Large Bitmaps Efficiently

中解释了整个问题