在附加到适配器的Gallery中显示位图时,“无法绘制可回收的位图”

时间:2012-08-31 16:07:05

标签: android

在Android 4.1中,对我来说,我们的应用程序中出现了看似奇怪的错误。在应用程序中,扩展BaseAdapter的自定义适配器附加到Gallery小部件。当从左到右快速滚动时,反之亦然,我得到一个带有异常消息的FC:

  

java.lang.IllegalArgumentException:无法绘制循环位图

getView(..)方法的代码如下:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    ViewHolder viewHolder;

    if (convertView == null){
        // View is not recycled. Inflate the layout.
        LayoutInflater vi = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        convertView = vi.inflate(R.layout.gallery_image, parent, false);

        viewHolder = new ViewHolder();
        viewHolder.image = (ImageView) convertView.findViewById(R.id.gallery_image);

        convertView.setTag(viewHolder);
    } else {
        viewHolder = (ViewHolder)convertView.getTag();
        viewHolder.image.setImageDrawable(null);
    }

    imageLoader.displayImage(images.get(position).getFilename(),
            images.get(position).getUrlThumbnail(),
            viewHolder.image,
            Math.round(BitmapUtil.convertDpToPixel(400f, context)),
            Math.round(BitmapUtil.convertDpToPixel(400f, context)));

    return convertView;
}

我想我应该在某处使ImageView无效,但我无法让它正常工作。 ImageLoader是一个(非常)简单的类,用于加载图像 - 来自LruCache,磁盘/ SD卡或远程获取它。

2 个答案:

答案 0 :(得分:15)

您收到此错误是因为您无法访问回收的Bitmap。正如Android开发者网站所述:

  

释放与此位图关联的本机对象,然后清除   参考像素数据。这不会释放像素数据   同步;它只是允许它被垃圾收集,如果有的话   没有其他参考。位图标记为“死”,意思是它   如果调用getPixels()或setPixels(),则会抛出异常   什么都不会。这个操作无法逆转,所以应该如此   只有在你确定没有进一步的用途时才被调用   位图。这是一个高级调用,通常不需要调用,   因为正常的GC过程会在没有时释放这个内存   更多对此位图的引用。

我建议你不要回收Bitmap到目前为止,因为它仍然有用。因此,请在调用recycle()方法时查看代码,然后将其删除。

当点到了不再需要使用Bitmap的地方时,我建议你使用这个方法来处理Bitmap:

public void disposeBitmap(Bitmap bitmap) {
        bitmap.recycle();
        bitmap = null;
}

我希望这会有所帮助。

答案 1 :(得分:8)

事实证明,这个错误是由我的班级oldBitmap.recycle()方法中的entryRemoved(..)调用覆盖LruCache引起的。由于位图可能仍附加到ImageView,因此调用recycle()会导致麻烦。

如果我理解正确:LruCache的缓存大小将在其构造函数中设置。当项目数超过此大小时,对象将有资格进行垃圾收集,这将在位图不再与ImageView关联时发生。

网上有很多示例和教程建议recycle()应调用entryRemoved(..),但从我看到的情况来看,这是错误的。