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

han*_*ide 15 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;
}
Run Code Online (Sandbox Code Playgroud)

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

Luk*_*lor 15

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

释放与此位图关联的本机对象,并清除对像素数据的引用.这不会同步释放像素数据; 如果没有其他引用,它只是允许它被垃圾收集.位图标记为"死",这意味着如果调用getPixels()或setPixels(),它将抛出异常,并且不会绘制任何内容.此操作无法撤消,因此只有在您确定位图没有进一步用途时才应调用此操作.这是一个高级调用,通常不需要调用,因为正常的GC进程将在没有更多对此位图的引用时释放此内存.

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

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

public void disposeBitmap(Bitmap bitmap) {
        bitmap.recycle();
        bitmap = null;
}
Run Code Online (Sandbox Code Playgroud)

我希望这有帮助.


han*_*ide 8

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

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

网上的很多示例和教程都表明recycle()应该调用它entryRemoved(..),但从我看到的情况来看,这是错误的.

  • 是的,假设你可以从`entryRemoved()`调用`recycle()`是不安全的. (2认同)