Recycle ImageView's Bitmap
Asked Answered
U

4

38

I have something like this:

Bitmap.Config conf = Bitmap.Config.ARGB_8888;
WeakReference<Bitmap> bm = new WeakReference<Bitmap>(Bitmap.createBitmap(3000 + 3000, 2000, conf));

Canvas canvas = new Canvas(bm.get());
canvas.drawBitmap(firstBitmap, 0, 0, null);
canvas.drawBitmap(bm, firstBitmap.getWidth(), 0, null);

imageView.setImageBitmap(bm);

And I apply this on more than 10 imageView's which are created one by one. Whenever I create new ImageView, I want to recycle the 'bm' object from the first one, cause this code up there, causes my heap to grow more and more and then throw OutOfMemoryError, so I do:

bm.recycle()

right after I set the Bitmap (bm) to the imageView object. This causes exception that the ImageView's canvas wants to draw recycled Bitmap.

What is the way to recycle a Bitmap that has already been put as image on ImageView?

Thanksb

Ul answered 10/8, 2011 at 10:9 Comment(1)
It's right after imageView.setImageBitmap(bm); and under that the block ends.. no other lines.Ul
R
56

In your onDestroy method you could try something like this:

ImageView imageView = (ImageView)findViewById(R.id.my_image);
Drawable drawable = imageView.getDrawable();
if (drawable instanceof BitmapDrawable) {
    BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
    Bitmap bitmap = bitmapDrawable.getBitmap();
    bitmap.recycle();
}

The cast should work since setImageBitmap is implemented as

public void setImageBitmap(Bitmap bm) {
    setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}
Ravin answered 10/8, 2011 at 10:30 Comment(3)
In his case, maybe it should be done right before he call setImageBitmap() again.Slavish
I don't have access to the Activity where the ImageView is used, I just implement custom ImageView, so I thought the ImageView class itself has some mechanism as destructor in C++ or any signal to know that the very instance of that ImageView is not used anymore..Ul
Do I have to do this for all images or just for large ones. can't I just assign another image to the image view?Callahan
H
2

If you set the same bitmap object on all your ImageViews, it shouldn't throw an OutOfMemoryError. Basically, this should work:

WeakReference<Bitmap> bm = new WeakReference<Bitmap>(Bitmap.createBitmap(3000 + 3000, 2000, Bitmap.Config.ARGB_8888));

Canvas canvas = new Canvas(bm.get());
canvas.drawBitmap(firstBitmap, 0, 0, null);
canvas.drawBitmap(bm, firstBitmap.getWidth(), 0, null);

imageView1.setImageBitmap(bm.get());
imageView2.setImageBitmap(bm.get());
imageView3.setImageBitmap(bm.get());
imageView4.setImageBitmap(bm.get());
imageView5.setImageBitmap(bm.get());
// ...

If this doesn't work, it simply means your bitmap is too large (6000x2000 pixels is about 12 megabytes, if I calculated right). You can either:

  • make your bitmap smaller
  • cut down on other stuff that use a lot of memory
Hughs answered 10/8, 2011 at 10:35 Comment(2)
The thing is that even though I recycle the Bitmap created with .createBitmap, the heap grows everytime this methods ends. I recycle it right after to check if it's ok - nope, the heap grows. So I suppose this is the leak..Ul
12Mpx != 12MB. It is probably taking a lot more memory than just 12MB. A 12Mpx Bitmap can take more than 35MB.Metage
G
1

Devconsole's answer is great, but you can also store all bitmap objects in list like member of your class, and then recycle them in cycle when the onDestroy() method of activity (or some other release lifecycle method of component where you use bitmap) will be called.

Gooch answered 16/2, 2015 at 15:24 Comment(0)
G
-1

Don't create images larger than you need at any one time. The heap limitations are designed to prevent you from hanging yourself and completely taking over the device's limited memory.

If you need more detail because you plan on zooming in, then re-render that portion of the image with higher detail at zoom time, excluding the portions you aren't viewing.

Grath answered 10/8, 2011 at 15:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.