13

我是所有内存管理主题的新手,所以有很多东西我不明白。
我正在尝试在我的应用程序中缓存图像,但我遇到了内存消耗问题:

所有的 Bitmap Chaching 代码都是从这里复制粘贴的:http: //developer.android.com/training/displaying-bitmaps/index.html

我在eclipse的DDMS视图中调试了代码并检查了堆大小,在这些代码行之后有大约15mb的跳转:

        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);

在“decodeSampledBitmapFromResource”方法中。

图片为 1024x800, 75kb jpg 文件。根据我在网上看到的,这张图片应该占用的内存量大约是 1024*800*4(Bytes per pixel)=3.125mb

关于这个主题的所有线程都没有说明为什么它占用的内存比它应该的多得多。有没有办法用合理的内存缓存一张图像?

编辑

我尝试使用下面@ArshadParwez 的答案中建议的 decodeFile 方法。使用这种方法,在 BitmapFactory.decodeStream 方法之后,内存只增加了 3.5mb - 问题解决了,有点,但我想直接从资源中缓存位图。

我注意到在 decodeResource 方法期间有 2 次内存“跳跃”——其中一次约为 3.5mb——这是合理的,另一次奇怪的是 14mb。那些 14mb 是用来做什么的,为什么会这样?

4

3 回答 3

8

图像也会根据密度进行缩放,因此它们可以使用大量内存。

例如,如果图像文件在drawable文件夹中(即mdpi密度)并且您在设备上运行它xhdpi,则宽度和高度都会加倍。也许这个链接可以帮助你,或者这个

因此,在您的示例中,图像文件将占用的字节数是:

(1024*2)*(800*2)*4 = 13,107,200 字节。

如果你在设备上运行它会更糟xxhdpi(比如 HTC one 和 Galaxy S4)。

你能做什么?将图像文件放入正确的密度文件夹(drawable-xhdpidrawable-xxhdpi)或放入drawable-nodpi(或资产文件夹)并根据您的需要缩小图像。

顺便说一句,您不必设置options.inJustDecodeBounds = false ,因为它是默认行为。事实上,您可以为位图选项设置 null。

关于缩小比例,您可以使用谷歌的方式我的方式,每种方式都有其优点和缺点。

关于缓存有很多方法可以做到这一点。最常见的一种是 LRU 缓存。还有一个我最近创建的替代方法(链接此处此处),它允许您缓存更多图像并避免出现 OOM,但它给您带来了很多责任。

于 2013-08-16T19:44:14.147 回答
7

您可以使用此方法传递图像并从中获取位图:

public Bitmap decodeFile(File f) {
    Bitmap b = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream(f);
        BitmapFactory.decodeStream(fis, null, o);
        fis.close();
        int IMAGE_MAX_SIZE = 1000;
        int scale = 1;
        if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
            scale = (int) Math.pow(
                    2,
                    (int) Math.round(Math.log(IMAGE_MAX_SIZE
                            / (double) Math.max(o.outHeight, o.outWidth))
                            / Math.log(0.5)));
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = new FileInputStream(f);
        b = BitmapFactory.decodeStream(fis, null, o2);
        fis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return b;
}
于 2013-08-15T15:09:21.907 回答
1

@Ori Wasserman:根据您的要求,我使用了一种从资源文件夹中获取图像的方法,并且我也使用了 7 MB 图像。我将 7 MB 图像放在“res->drawable”文件夹中,使用以下代码它没有崩溃,图像显示在 imageview 中:

 Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.image_7mb);
 loBitmap = Bitmap.createScaledBitmap(image, width_of_screen , height_of_screen, true);
 imageview.setImageBitmap(loBitmap);
于 2013-08-16T16:28:08.003 回答