1

I was using following code in onDestroy to recycle large bitmap in order to restore memory quickly. If I don't do it, application will crash with OutOfMemory error after few screen rotations. Android sucks at handling memory.

ImageView imgBG = (ImageView)findViewById(R.id.mainBG);
if (imgBG != null)
{
    ((BitmapDrawable)imgBG.getDrawable()).getBitmap().recycle();
    imgBG.setImageDrawable(null);
}
System.gc();

Unfortunetely, things changed in ICS. They started caching resources and recycling a bitmap actually recycles the bitmap in cache. Android isn't smart enough to figure it out and it's trying to use the recycled bitmap in the future, which results in this:

java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@40f44390
at android.graphics.Canvas.throwIfRecycled(Canvas.java:1047)
at android.graphics.Canvas.drawBitmap(Canvas.java:1151)
at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:400)
at android.widget.ImageView.onDraw(ImageView.java:973)
at android.view.View.draw(View.java:11014)
at android.view.ViewGroup.drawChild(ViewGroup.java:3186)
at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2788)
at android.view.ViewGroup.drawChild(ViewGroup.java:3184)
[...]

So here's the problem. If I recycle it, it will crash on ICS. If I don't, the app will run out of memory. What should I do? What's the right way to free the memory, which actually works?

Sebastian Nowak
  • 5,607
  • 8
  • 67
  • 107
  • I think this caching (sharing) is done even in Android 2.3, perhaps just not so aggressively. As far as I know, however, it does it **only** for XML-defined bitmaps. Did you try loading your bitmap via decodeBitmap, and then setting to to the view? In this case, Android will not use the system cache, hopefully. Let me know how it goes, as I also had similar issue and look forward to your experience. – Thomas Calc Jul 26 '12 at 00:22

1 Answers1

-3

Try this:

ImageView imgBG = (ImageView)findViewById(R.id.mainBG);
if (imgBG != null)
{
    BitmapDrawable drawable = ((BitmapDrawable)imgBG.getDrawable()).getBitmap();
    imgBG.setImageDrawable(null);
    drawable.recycle();
}
System.gc();
Superbiji
  • 1,723
  • 2
  • 14
  • 21
  • That's exactly what I'm doing and my question explains why this approach is now WRONG. You cannot recycle the bitmap. – Sebastian Nowak Jul 21 '12 at 07:52
  • according to exception thrown: maybe there is a different thread for UI update? which is asking for recycled bitmap. thats why I store the bitmap to drawable first, set null, then recycle. – Superbiji Aug 02 '12 at 07:32
  • Stop guessing and just read my question. It explains while `recycle()` fails and why such approach is wrong. – Sebastian Nowak Aug 02 '12 at 12:51