最近,我开始使用 Google ImageWorker 类在后台线程上加载位图。此类处理所有事情,包括将位图放入 ImageView。 Google 在此处讨论此类(以及图像处理和缓存的辅助类):http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
在我的例子中,ImageView 是 ListView 中列表项的一部分。这是我的 ArrayAdapter 上 getView 的有趣部分:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView == null ? inflater.inflate(R.layout.nodelist_item, null) : convertView;
NodeHolder holder = getHolder(view);
Node node = mList.get(position);
holder.txtTitle.setText(node.Title);
//Setting the rest of the different fields ...
//And finally loading the image
if(node.hasArt())
worker.loadImage(node.ImageID, holder.imgIcon);
}
完整的 getView 方法可以在这里看到:http://pastebin.com/CJbtVfij
worker 对象是 ImageWorker 的一个非常简单的实现:
public class NodeArtWorker extends ImageWorker {
protected int width;
protected int height;
public NodeArtWorker(Context context) {
super(context);
addImageCache(context);
//Code for getting the approximate width and height of the ImageView, in order to scale to save memory.
}
@Override
protected Bitmap processBitmap(Object data) {
Bitmap b = getBitmap(data);
if(b == null) return null;
return Utils.resizeBitmap(b, width, height);
}
protected Bitmap getBitmap(Object data) {
//Downloads the bitmap from a server, and returns it.
}
}
这很好用,现在性能比以前好很多。但是,如果我更改列表中某些项目的 ImageID,并调用 adapter.notifyDataSetChanged() 来重建 View (从而开始加载新的位图),我会得到一个 RuntimeException:
0 java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@41adf448
1 at android.graphics.Canvas.throwIfRecycled(Canvas.java:1058)
2 at android.graphics.Canvas.drawBitmap(Canvas.java:1159)
3 at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:440)
4 at android.widget.ImageView.onDraw(ImageView.java:1025)
5 at android.view.View.draw(View.java:14126)
完整的堆栈跟踪可以在下面的 pastebin 条目中看到,但可能没有意思,因为它是典型的 Android View 层次结构重绘堆栈跟踪:http://pastebin.com/DsWcidqw
我知道位图正在被回收,但我不明白在哪里以及可以做什么。由于我的代码直接来自 Google,据我所知,这是推荐的这样做方式,我很困惑。
最佳答案
在 Android 上,Bitmap
可以回收以供以后重新使用(比重新创建 Bitmap 快得多)。
Bitmap#recycle()
方法会将位图标记为已回收。
因此,如果您尝试将这样的回收位图设置为 ImageView 或在 Canvas 上绘制它,您最终会遇到以下异常:
java.lang.RuntimeException: Canvas: trying to use a recycled bitmap
您在问题中链接的官方演示是处理回收的Bitmap
s。
它使用专用方法 hasValidBitmap()
并检查 Bitmap#isRecycled()
值:
private synchronized boolean hasValidBitmap() {
Bitmap bitmap = getBitmap();
return bitmap != null && !bitmap.isRecycled();
}
所以你也需要这样做。当您在缓存中搜索 Bitmap 时,在将其应用于 ImageView 之前,请检查它是否被回收。如果不是可以直接设置,否则需要更新Bitmap。
要从回收的位图创建新的位图,您可以使用 Bitmap::createBitmap(Bitmap)方法。
您可以在 this page 上找到更多详细信息.
关于android - 使用 Google 的 ImageWorker 在 ListView 中加载图像导致 java.lang.RuntimeException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25390551/