11

I'm getting this exception:

Exception: java.lang.IllegalStateException: Can't copy a recycled bitmap

My code is:

    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);
    }

If the exception is telling me that I've recycled resizedBitmap, that is patently false! What am I doing wrong??

Richard Eng
  • 1,954
  • 6
  • 23
  • 32
  • It is likely that when you assign into `resizedBitmap`, it requires the original and is still tied to it. – cdeszaq Jan 30 '12 at 22:19
  • You've got to be kidding! You mean createBitmap does not create a totally new bitmap that is different from 'bitmap'?? WTF. – Richard Eng Jan 30 '12 at 23:08
  • it would be usefull if the logcat is attached for stack trace...don't catch the exception... – Navin Ilavarasan Jan 30 '12 at 23:46
  • yes, createBitmap can return the source bitmap: `// check if we can just return our argument unchanged if (!source.isMutable() && x == 0 && y == 0 && width == source.getWidth() && height == source.getHeight() && (m == null || m.isIdentity())) { return source; }` – 3dmg Aug 22 '18 at 11:51

2 Answers2

14

You are actually calling bitmap.recycle(); after this line:

Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);
bschultz
  • 4,244
  • 1
  • 25
  • 33
  • Did you read the last line of the OP? He indicates that the exception says he recycled `resizedBitmap`. – cdeszaq Jan 30 '12 at 22:20
  • Exactly. Which he said he isn't doing, but he clearly does. The exception clearly states the problem. – bschultz Jan 30 '12 at 22:22
  • I think the issue is that the code should copy the bitmap _and then_ recycle it, based on the order of the expressions. The fact that the runtime seems to do them out of order is, I believe, the source of confusion. – cdeszaq Jan 30 '12 at 22:25
  • Also, the copy that is throwing the error is the one within the `try{` block, which is attempting to copy `resizedBitmap` and store it in `bitmap`, and is _not_ trying to copy `bitmap`. – cdeszaq Jan 30 '12 at 22:26
  • Agreed. He should change the order and see if his result is different. – bschultz Jan 30 '12 at 22:27
  • Correct, but maybe it cannot be stored into bitmap because it's been recycled. I'm not quite sure to be honest. Lol. – bschultz Jan 30 '12 at 22:30
  • You mean createBitmap does not create a totally new bitmap that is different from 'bitmap'?? That's not at all intuitive. It's a pretty stupid design! – Richard Eng Jan 30 '12 at 23:11
  • True, but we don't know why exactly he needs to do it in this way. He may have a good reason...? Lol – bschultz Jan 30 '12 at 23:26
  • 3
    Okay, I accept the answer. It's idiotic, but what can you do? At least, it works. – Richard Eng Jan 30 '12 at 23:57
7

Quote from Bitmap.createBitmap() method's Javadoc:

Returns an immutable bitmap from subset of the source bitmap, transformed by the optional matrix. The new bitmap may be the same object as source, or a copy may have been made. It is initialized with the same density as the original bitmap. If the source bitmap is immutable and the requested subset is the same as the source bitmap itself, then the source bitmap is returned and no new bitmap is created.

That mean that in some cases, i.e. when asking to resize a source bitmap to its actual size, there will be no difference between source and resized bitmap. To save memory the method will just return the same instance of bitmap.

To fix your code you should check whether a new bitmap has been created:

Bitmap resizedBitmap = Bitmap.createBitmap(sourceBitmap, 0, 0, width, height, matrix, true);
if (resizedBitmap != sourceBitmap) {
    sourceBitmap.recycle();
}
xsveda
  • 17,074
  • 2
  • 16
  • 16