2

I've got a utility method (below) that resizes a bitmap and gives me back a new version. Since I am doing this with quite a few images & I wanted to reduce the chance of running out of memory, I've recycled the bitmap after usage.

This works fine on almost all devices. However, I've notice on the samsung galaxy tab 3 (10 inch) and the note 10.1 (2014) I'm getting the below stack traces:

java.lang.IllegalArgumentException: Cannot draw recycled bitmaps
at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:756)
at android.view.GLES20RecordingCanvas.drawBitmap(GLES20RecordingCanvas.java:104) 

Below is my resize code:

private static Bitmap resizeBitmap(int newWidth, int newHeight, Bitmap bitmapResize) {
    if (bitmapResize == null) {
        return null;
    }

    int width = bitmapResize.getWidth();
    int height = bitmapResize.getHeight();

    float scaleWidth = ((float) newWidth) / width;
    float scaleHeight = ((float) newHeight) / height;

    Matrix matrix = new Matrix();
    matrix.postScale(scaleWidth, scaleHeight);

    Bitmap resizedBitmap = Bitmap.createScaledBitmap(bitmapResize,
            newWidth, newHeight, true);

    //SHOULD I DO THIS???
    bitmapResize.recycle();
    return resizedBitmap;
}

I have not figured out why almost all devices work, except those 2 (there may be more). The emulator shows no issues either.

It might be worth noting, not all images give me a "Cannot draw recycled bitmaps" error. Only some. But its consistently the same images.

(In case its of use, my app runs on 2.2 upwards)

Bruce Lowe
  • 6,063
  • 1
  • 36
  • 47

3 Answers3

5

I've managed to find the solution to my issue. It turns out the original image may be passed back as an optimisation, if the width/height of the resize match the original image.

I imagine on some devices my computations resulted in me trying to resize an image to its existing size. When i recycled the "old" bitmap, i was recyling the resized one too.

The solution is to change my code to say

if (bitmapResize!=resizedBitmap )
    bitmapResize.recycle();

I found my issue covered in this conversation ( which i didn't find in my initial searching for the issue)

https://groups.google.com/forum/#!topic/android-developers/M6njPbo3U0c

Bruce Lowe
  • 6,063
  • 1
  • 36
  • 47
0

I had a similar issue with on of ma games and from my experience you are doing the right thing. its the right place to recycle the old bitmap and will prevent OutOfMemoryExceptions, keep in mind that this instance of Bitmap will not be usable anymore.

Nir Hartmann
  • 1,389
  • 12
  • 14
  • Thanks, any idea why I get "Cannot draw recycled bitmaps" then on a couple of devices? – Bruce Lowe Feb 10 '14 at 14:31
  • Do you have any views that uses the old bitmap ? this kind of errors is mostly thread safety issues. – Nir Hartmann Feb 10 '14 at 14:38
  • I don't use the original image - also its consistently on a galaxy tab 3, but I can't replicate on other devices - I'd imagine threading issues would occur on all devices and not be consistent. – Bruce Lowe Feb 10 '14 at 15:30
0

You may simply use input bitmap reference as output. This way your input bitmap will be overwritten and you won't need to recycle it.

Kind of:

private static Bitmap resizeBitmap(int newWidth, int newHeight, Bitmap bitmapResize) {
if (bitmapResize == null) {
    return null;
}

int width = bitmapResize.getWidth();
int height = bitmapResize.getHeight();

float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;

Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);

return Bitmap.createScaledBitmap(bitmapResize,
        newWidth, newHeight, true);

}

Sam
  • 1,652
  • 17
  • 25
  • I tried that approach, recycling seems to prevent outofmemory exception better – Nir Hartmann Feb 10 '14 at 14:27
  • according to another post, the recycle may be needed on older versions of android : http://stackoverflow.com/questions/11954435/what-does-calling-bitmap-recycle-on-api-11-do. I didn't mention it (until now), but my app does run on android 2.2 / level 8. – Bruce Lowe Feb 10 '14 at 14:31
  • 1
    you are not doing that. You are not overwritting your input bitmap (whatever that means). You are simply not creating a local variable to hold it, which changes nothing at all. – njzk2 Feb 10 '14 at 15:46