回收ImageView的位图

38

我有类似以下的东西:

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);

我将此应用于一个一个创建的10多个imageView上。每当我创建新的imageView时,我想回收来自第一个imageView的'bm'对象,因为上面的代码会导致我的堆越来越大,然后抛出 OutOfMemoryError。因此,我这样做:

bm.recycle()

在我将Bitmap(bm)设置为imageView对象后,立即出现异常。这导致ImageView的画布想要绘制已回收的Bitmap。

有什么方法可以回收已经作为图像放置在ImageView上的Bitmap吗?

谢谢。


就在imageView.setImageBitmap(bm);之后,而且在那个代码块结束之前。没有其他的行了。 - Peter Olsbourg
4个回答

56

在您的onDestroy方法中,您可以尝试像这样做:

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();
}

这个转换应该有效,因为setImageBitmap的实现方式是

public void setImageBitmap(Bitmap bm) {
    setImageDrawable(new BitmapDrawable(mContext.getResources(), bm));
}

在这种情况下,也许应该在他再次调用setImageBitmap()之前进行操作。 - user802421
我无法访问使用ImageView的Activity,我只是实现自定义ImageView,因此我认为ImageView类本身具有类似C++中的析构函数或任何信号的机制,以知道该ImageView的实例不再使用。 - Peter Olsbourg
我必须为所有图片都这样做,还是只针对大图片?我不能只将另一张图片分配给图像视图吗? - hasan

2

如果您在所有ImageView上设置相同的位图对象,则不应抛出OutOfMemoryError。基本上,这应该可以工作:

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());
// ...

如果这样做不起作用,那就意味着你的位图太大了(如果我计算正确,6000x2000像素大约是12兆字节)。你可以选择:
  • 缩小位图的大小
  • 减少其他占用大量内存的内容

问题在于,即使我使用.createBitmap创建的位图进行回收,每次该方法结束时堆都会增长。我立即对其进行回收以检查是否正常 - 不行,堆仍然增长。因此,我认为这就是泄漏的原因。 - Peter Olsbourg
12Mpx不等于12MB。它可能占用的内存远远超过12MB。一个12Mpx位图可能需要超过35MB的内存。 - diego nunes

1
Devconsole的回答很好,但你也可以将所有位图对象存储在类成员列表中,然后在activity的onDestroy()方法(或其他使用位图的组件的某些释放生命周期方法)周期性地回收它们。

-1

不要一次创建比你需要的更大的图像。堆限制旨在防止您自己挂起并完全占用设备的有限内存。

如果您需要更多细节,因为您计划放大,则在缩放时重新呈现该图像部分以获得更高的细节,不包括您未查看的部分。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接