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

Peter Olsbourg
  • 487
  • 2
  • 7
  • 12

4 Answers4

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));
}
dvs
  • 12,324
  • 6
  • 38
  • 45
devconsole
  • 7,875
  • 1
  • 34
  • 42
  • In his case, maybe it should be done right before he call `setImageBitmap()` again. – user802421 Aug 10 '11 at 10:36
  • 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.. – Peter Olsbourg Aug 10 '11 at 10:42
  • 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? – hasan Jan 29 '14 at 08:16
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
Felix
  • 88,392
  • 43
  • 149
  • 167
  • 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.. – Peter Olsbourg Aug 10 '11 at 11:08
  • 12Mpx != 12MB. It is probably taking a lot more memory than just 12MB. A 12Mpx Bitmap can take more than 35MB. – diego nunes Jul 21 '15 at 03:38
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.

-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.

Josh
  • 10,618
  • 2
  • 32
  • 36