【问题标题】:Android out of memory exception with bitmaps位图的Android内存不足异常
【发布时间】:2013-02-22 18:09:31
【问题描述】:

首先,我阅读了很多关于内存不足异常的帖子和文章,但没有一篇对我的情况有所帮助。我要做的是从 sd 卡加载图像,但将其缩放到精确的像素大小。

我先得到图片的宽高,然后计算样本大小:

    final BitmapFactory.Options options = new BitmapFactory.Options();
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile(backgroundPath, options);

    // Calculate inSampleSize
    options.inSampleSize = calculateInSampleSize(options, getWidth(), getHeight());

这是我获取样本大小的方法(尽管它并不真正相关):

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;

    // NOTE: we could use Math.floor here for potential better image quality
    // however, this also results in more out of memory issues
    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;
}

现在我有了样本大小,我将图像从磁盘加载到近似大小(样本大小):

    // Decode bitmap with inSampleSize set
    options.inJustDecodeBounds = false;
    options.inPurgeable = true;
    Bitmap bmp = BitmapFactory.decodeFile(backgroundPath, options);

现在,我将创建的这个位图缩放到我需要的确切大小并进行清理:

    // scale the bitmap to the exact size we need
    Bitmap editedBmp = Bitmap.createScaledBitmap(bmp, (int) (width * scaleFactor), (int) (height * scaleFactor), true); 

    // clean up first bitmap
    bmp.recycle();
    bmp = null;
    System.gc();    // I know you shouldnt do this, but I'm desperate 

上述步骤通常是让我的内存不足异常。有谁知道如何从磁盘加载精确大小的位图以避免像上面那样创建两个单独的位图?

此外,当用户第二次运行此代码(设置新图像)时,似乎会发生更多异常。但是,我确保卸载从位图创建的可绘制对象,以便在再次运行此代码之前对其进行垃圾收集。

有什么建议吗?

谢谢, 尼克

【问题讨论】:

  • 在创建 editedBmp 之前,记录它的宽度和高度,以及 scaleFactor 以确保您的参数正确。
  • 代替 createScaledBitmap 你能做这里做的事情吗? developer.android.com/training/displaying-bitmaps/… ,只需将 decodeResources 更改为 decodeFile 并传入大小选项?
  • @Jave 是的,宽度、高度和比例因子是正确的。内存不足异常并不总是发生,当它不发生时,图像的大小是正确的。
  • @JohnBoker 该示例使用样本大小(类似于我在第一步中所做的)。这只会给你一个大概的尺寸,而不是它需要的实际尺寸。
  • 通过解码然后缩放到精确大小,位图分配的内存使用量增加了一倍。为什么不直接使用 bmp?如果它进入 ImageView,您可以使用 ScaleType 来比较插值与裁剪。

标签: android memory memory-management bitmap out-of-memory


【解决方案1】:

在您的情况下,执行第一次解码后无需创建中间位图。由于您是在画布上绘图,因此您可以使用以下任一方法(您认为最方便的方法)将图像缩放到完美尺寸。

drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)

drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint)

【讨论】:

    【解决方案2】:

    也许这种方法会有所帮助,我想我自己是从 stackoverflow 中提取出来的。它解决了我的内存不足异常问题。

    private Bitmap decodeFile(File f){
        try {
            //Decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(f),null,o);
    
            //The new size we want to scale to
            final int REQUIRED_SIZE=250;
    
            //Find the correct scale value. It should be the power of 2.
            int scale=1;
            while(o.outWidth/scale/2>=REQUIRED_SIZE && o.outHeight/scale/2>=REQUIRED_SIZE)
                scale*=2;
    
            //Decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize=scale;
            return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
        } catch (FileNotFoundException e) {}
    
        return null;
    } 
    

    【讨论】:

    • 这使用了一个样本大小,就像我在问题的第一步中所做的那样。这不会为您提供所需尺寸的确切尺寸。
    • 我认为您正在使用的 Bitmap.createScaledBitmap() 调用将完整的位图带入内存。我使用上述方法创建一个缩放位图,然后在返回的位图上使用 Bitmap.createScaledBitmap() 将其调整为我需要的最终尺寸。对不起,我没有帮到你。
    猜你喜欢
    • 2013-06-24
    • 1970-01-01
    • 1970-01-01
    • 2016-08-23
    • 1970-01-01
    • 2014-03-13
    • 2012-10-24
    • 2023-03-06
    相关资源
    最近更新 更多