【问题标题】:What's wrong with this inSampleSize calculating method for Bitmaps? Out of memory这个 inSampleSize 的 Bitmaps 计算方法有什么问题?内存不足
【发布时间】:2015-05-12 13:25:32
【问题描述】:

在我的应用程序中,我正在遍历图像的 URL,解码并将它们放入 ArrayList<Bitmap>

它们的大小可能相差很大,所以我正在使用inJustDecodeBounds = true 选项进行“预解码”,以计算实际解码所需的inSampleSize 值。

请看下面我的方法,我希望它不会太难理解。基本上我的目标是与设备的屏幕尺寸相似。

for (Element e: posts) {
    if (!e.id().equals("")) {
        //preparing decode
        options = new BitmapFactory.Options();
        input = new URL(e.url).openStream();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(input, null, options);
        input.close();

        //setting inSampleSize if necessary
        int picPixels = options.outWidth * options.outHeight;
        int picScreenRatio = picPixels / screenPixels;
        if (picScreenRatio > 1) {
            int sampleSize = picScreenRatio % 2 == 0 ? picScreenRatio : picScreenRatio + 1;
            options.inSampleSize = sampleSize;
        }

        //actual decode
        input = new URL(e.url).openStream();
        options.inJustDecodeBounds = false;
        Bitmap pic = BitmapFactory.decodeStream(input, null, options);
        input.close();

        picList.add(pic);
    }
}

计算screenPixels的代码:

Display display = getWindowManager().getDefaultDisplay();
Point screenSize = new Point();
display.getSize(screenSize);
int screenPixels = screenSize.x * screenSize.y;

我浏览了大约 60 张图片,其中大约 40 张我的应用因java.lang.OutOfMemoryError 而崩溃。

据我了解,inJustDecodeBounds = true 没有分配内存,如果我的方法是正确的(我相信它是正确的),那么非常大的图像会变得非常大 inSampleSizes,所以我不知道可能是什么问题。

不胜感激。

【问题讨论】:

    标签: java android bitmap


    【解决方案1】:

    无论您使用 inSampleSize,您都无法轻松地将 60 个与屏幕一样大的位图保存在内存中。

    假设你得到一个全高清屏幕大约1920*1080*60*4字节。

    这大约是 500 MB 的数据。 您需要以某种方式更改您的位图加载逻辑。

    this 答案中,您可以了解可以计算多少内存。因设备而异。

    但始终尽量让您的应用程序尽可能节省内存。

    【讨论】:

    • 我很确定这是问题所在,不知道为什么我没有想到这个。谢谢。
    【解决方案2】:

    样本大小必须是 2 的幂。来自文档:

    如果设置为大于 1 的值,则请求解码器对原始图像进行二次采样 图像,返回较小的图像以节省内存。样本量为 任一维度中对应于单个维度的像素数 解码位图中的像素。例如, inSampleSize == 4 返回一个 图像的宽度/高度为原件的 1/4,原件的 1/16 像素数。任何值

    下面是Android - Volley 库中关于如何为位图找到最佳样本大小的一个好技巧:

        int findBestSampleSize(int actualWidth, int actualHeight, int desiredWidth, int desiredHeight) {
            double wr = (double) actualWidth / desiredWidth;
            double hr = (double) actualHeight / desiredHeight;
            double ratio = Math.min(wr, hr);
            float n = 1.0f;
            while ((n * 2) <= ratio) {
                n *= 2;
            }
    
            return (int) n;
        }
    

    【讨论】:

      【解决方案3】:

      众所周知,在 Android 上进行图像处理非常困难。我建议您使用已建立的图像管理库,例如 Facebook's Fresco:

      https://github.com/facebook/fresco

      他们的文档中的一个例子:

      Fresco 的 Drawees 会为您显示一个占位符,直到图像加载完毕,并在图像到达时自动显示给图像。当图像离开屏幕时,它会自动释放内存。

      还有:

      使用 Fresco 的应用甚至可以在低端设备上运行,而无需不断努力控制其图像内存占用。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-04-10
        • 2021-01-10
        • 1970-01-01
        • 2012-06-22
        • 2015-12-30
        • 2021-09-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多