回收位图异常

11

我遇到了这个异常:

异常:java.lang.IllegalStateException: 无法复制已回收的位图

我的代码如下:

    int width = bitmap.getWidth();
    int height = bitmap.getHeight();
    int newWidth;
    int newHeight;
    if (width >= height) {
        newWidth = Math.min(width,1024);
        newHeight = (int) (((float)newWidth)*height/width);
    }
    else {
        newHeight = Math.min(height, 1024);
        newWidth = (int) (((float)newHeight)*width/height);
    }
    float scaleWidth = ((float)newWidth)/width;
    float scaleHeight = ((float)newHeight)/height;

    Matrix matrix = new Matrix();
    matrix.postScale(scaleWidth, scaleHeight);
    switch (orientation) {
    case 3:
        matrix.postRotate(180);
        break;
    case 6:
        matrix.postRotate(90);
        break;
    case 8:
        matrix.postRotate(270);
        break;
    }
    Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
    bitmap.recycle();
    try {
        bitmap = resizedBitmap.copy(resizedBitmap.getConfig(), true);
    }
    catch (Exception e) {
        Log.v(TAG,"Exception: "+e);
    }

如果异常告诉我我已经回收了resizedBitmap,那是绝对错误的!我做错了什么?

当您将值分配给resizedBitmap时,很可能需要原始值并且仍然与其相关联。 - cdeszaq
你开玩笑吧!你的意思是createBitmap不会创建一个与“bitmap”不同的全新位图??真是见鬼了。 - Richard Eng
如果附上Logcat用于堆栈跟踪会很有帮助……不要捕获异常。 - Navin Ilavarasan
是的,createBitmap可以返回源位图: // 检查是否可以直接返回我们的参数 如果(!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() && height == source.getHeight() && (m == null || m.isIdentity())) { 返回源; } - 3dmg
2个回答

14

在这行代码之后,你实际上正在调用 bitmap.recycle();

Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

我认为问题在于代码应该按照表达式的顺序先复制位图,然后再回收它。运行时似乎是按照错误的顺序执行这些操作,这就是混淆的根源。 - cdeszaq
此外,引发错误的副本是 try{ 块内部的副本,它试图复制 resizedBitmap 并将其存储在 bitmap 中,并且 不是 尝试复制 bitmap - cdeszaq
同意。他应该改变顺序,看看结果是否不同。 - bschultz
正确,但可能无法存储到位图中,因为它已被回收。老实说,我不太确定。哈哈。 - bschultz
3
好的,我接受这个答案。虽然有点蠢,但是能怎么办呢?至少它有效。 - Richard Eng
显示剩余4条评论

8

Bitmap.createBitmap()方法的Javadoc中引用了以下内容:

从源位图的子集中返回一个不可变位图,可通过可选矩阵进行转换。新位图可能与源相同,也可能已经复制。它以与原始位图相同的密度初始化。如果源位图是不可变的,并且请求的子集与源位图本身相同,则返回源位图,并且不创建新位图。

这意味着在某些情况下,例如当要求将源位图调整为其实际大小时,调整后的位图之间没有区别。为了节省内存,该方法将只返回位图的同一实例

要修复代码,您应该检查是否创建了新位图:

Bitmap resizedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, width, height, matrix, true);
if (resizedBitmap != sourceBitmap) {
    sourceBitmap.recycle();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接