Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android telling me my bitmap is recycled before I've actually recycled it

I'm getting my bitmap like so from XML:

//Get bitmap from drawable
bd = (BitmapDrawable) view.getResources().getDrawable(R.drawable.backgrounds);
backgrounds = bd.getBitmap();

//Do required work with bitmap (Will just use a log statement here for testing
Log.v("NewTag","Testing: "+bd.getBitmap().getPixel(0, 0));

//Now recycle this large bitmap
bd.getBitmap.recycle();
bd=null;
backgrounds.recycle();
backgrounds=null;

The first time I run this code, all is good. However when I exit my app (using the back key), then restart the app, it may or may not work. Sometimes, I get an error:

Can't call getPixel() on a recycled bitmap

Why? I've not even recycled it yet. Or more accurately, it seems to not be recreating the bitmap and remembering the recycle from last time.

This problem doesn't happen if I use BitmapFactory to obtain the bitmap (unfortunately, I can't do that as I have to get this particular bitmap from an XML alias).

Also prior to installing Lollipop, this worked OK (as long as I had bd = null).

I've been at this problem for 2 days straight so if anyone could throw any light on it I'd be very grateful.

Edit

I've attempted @aga's suggestion of simply not recycling/nulling bd, but this makes no difference. The bitmap is still 'already' recycled as soon it's been re-created (again, intermittently).

Also, when logging like so:

Log.v("NewTag","Backgrounds: "+backgrounds);

I've noticed that when it fails, the reference logged is the same as the previous time. So.....

enter image description here

like image 484
Zippy Avatar asked Mar 18 '23 11:03

Zippy


2 Answers

The Resources class has caches for resources loaded from your APK. When you recycle the Drawable and Bitmap, you ruin the cached objects. There is no way for the Resources caches to know this, so they happily return you the same object the next time you ask for that resource.

When your app process dies, all memory state is lost, including the resource cache -- so things will work again (once). Note that "exiting" the app or destroying the activity doesn't necessarily mean that your process will die.

like image 139
Snild Dolkow Avatar answered Mar 20 '23 00:03

Snild Dolkow


Interesting issue. I'm pretty sure, there were some optimization ideas behind it in Android.

If you do need XML's bitmaps:

    Resources res = new Resources(getAssets(), new DisplayMetrics(), new Configuration());

    bd = (BitmapDrawable) res.getDrawable(R.drawable.bitmap_drawable);
    backgrounds = bd.getBitmap();

    ......

    bd.getBitmap().recycle();
    bd=null;
    backgrounds.recycle();
    backgrounds=null;

Optionaly, you can first try to get Bitmap from standard getResources() and only then instantiate new resource instance.

If you don't need XML's bitmaps:

 Bitmap backgrounds = BitmapFactory.decodeResource(getResources(), R.drawable.test_image);

to get image and

 backgrounds.recycle();
 backgrounds=null;

to recycle it.

I hope, it helps.

like image 26
Konstantin Loginov Avatar answered Mar 20 '23 01:03

Konstantin Loginov