位图回收利用

4

我正在处理涉及位图的项目。因为我不想出现内存不足错误,所以我试图回收每个未使用的位图。不幸的是,我回收了太多,导致出现“尝试使用已回收的位图”错误。

我正在使用:

 Bitmap.createBitmap(bmp, x,y,w,h, matrix, false);
 Bitmap.createScaledBitmap(bmp, w, h,true);

这些方法后我应该回收bmp吗?还是它们会自动回收?例如:

Bitmap newBitmap = Bitmap.createBitmap(bmp, x,y,w,h, matrix, false);
bmp.recycle();

我可以在imageView.setImageBitmap()之后回收之前用过的图片吗?例如:

myImageView.setImageBitmap(myBitmap);
myImageView.setImageBitmap(newBitmap);
myBitmap.recycle();

感谢您的帮助。

在创建位图时,考虑使用BitmapFactory.Options。特别是要注意inPurgeable... http://developer.android.com/reference/android/graphics/BitmapFactory.Options.html - Salil Pandit
“尝试使用已回收的位图”是您关于已回收的位图看到的确切且唯一的错误吗?如果是,那么分析堆栈跟踪并查看错误发生时是否可以检测到模式可能是值得尝试的(虽然在框架中有一个中心位置抛出此异常,但代码有很多种方式可以到达该位置)。 - Joe
3个回答

9

当您不再需要位图时,应该仅对其进行回收。然而,当您想要显示它时,您确实需要一个位图。如果您不想显示它,则可以回收位图。


1
所以这是一个好的实践方式:myImageView.setImageBitmap(myBitmap); newBitmap = Bitmap.createBitmap(myBitmap,x,y,w,h, matrix, false); myImageView.setImageBitmap(newBitmap); myBitmap.recycle(); - ania
3
不,这样做行不通,将会出现异常,因为在位图呈现之前它就被回收了。调用setImageBitmap并不会立即将位图呈现到屏幕上,而是会在下一次UI更新周期的某个时刻发生。即使在此之后,你仍需要保留位图,因为你将其分配给了ImageView。只要你不再使用ImageView或者设置了不同的位图,就可以回收旧位图。在Activity.onStop()中回收所有旧的位图是一个安全的地方。你也可以使用onPause,但这样你必须在onResume中重新创建它们。 - tiguchi
@NobuGames 非常感谢,这对我帮助很大。我有一个小问题,作为Android的初学者,我想知道我们是通过回收旧位图来节省内存,但我们却创建了一个新的位图,我不明白这样做的好处在哪里?我们如何节省内存? - Lily
@NobuGames 好的,那很有道理。我有一个问题。如果我的应用程序根据从计算机发送的值绘制条形图,每秒钟更新一次此信息,并通过调用绘图类来更新绘图。在我的绘图类中,我有两个位图,一个是我分配给画布并重复使用它来绘制新的绘图,另一个是我分配给ImageView并在onStop时回收它。我遇到了内存不足错误,当我查看日志时,发现有很多GC(大约每半秒钟1次)。我做错了什么? - Lily
@Lily 很难确定,但我猜测你与计算机的通信代码可能是导致持续垃圾回收的原因,而不是你的绘图例程。绘制位图不会触发垃圾回收。你的应用程序如何与计算机进行通信? - tiguchi
显示剩余6条评论

1

只有在完成位图的使用并确定不再需要其中的数据时,才应该对其进行回收。这不是一种可以随意使用的魔法方法,用于处理位图时获取更多内存。


0

当我想要缩放位图时,我使用相同的引用:

Bitmap bmp = Bitmap.createBitmap(bmp, x,y,w,h, matrix, false); 

当第一个位图对象失去其引用“bmp”时,它会被垃圾回收器(GC)移除,因此您不需要回收任何东西。至于图像视图,它只将其源引用为“newBitmap”,而不创建自己的引用。

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