Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Cannot draw recycled bitmaps" when displaying bitmaps in Gallery attached to Adapter

Tags:

android

In Android 4.1 a, to me, seemingly strange error occurs in our app. In the app a custom adapter extending BaseAdapter is attached to a Gallery widget. When scrolling fast left-to-right and vice versa I get a FC with the exception message:

java.lang.IllegalArgumentException: Cannot draw recycled bitmap

Code for the getView(..) method is as follows:

@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;
}

I guess I should null the ImageView somewhere, but I cannot get it to work correctly. ImageLoader is a (quite) simple class for loading the images - either from LruCache, disk/sdcard or fetch it remotely.

like image 621
hanspeide Avatar asked Aug 31 '12 16:08

hanspeide


2 Answers

You are getting this error because you cannot access a recycled Bitmap. As the Android Developer site states:

Free the native object associated with this bitmap, and clear the reference to the pixel data. This will not free the pixel data synchronously; it simply allows it to be garbage collected if there are no other references. The bitmap is marked as "dead", meaning it will throw an exception if getPixels() or setPixels() is called, and will draw nothing. This operation cannot be reversed, so it should only be called if you are sure there are no further uses for the bitmap. This is an advanced call, and normally need not be called, since the normal GC process will free up this memory when there are no more references to this bitmap.

I suggest you don't recycle the Bitmap up to this point, since there is still use for it. So go look in your code for when you call the recycle() method and then delete it.

When the point comes where the Bitmap doesn't need to be used anymore, then I suggest you use this method to dispose the Bitmap:

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

I hope this helps.

like image 134
Luke Taylor Avatar answered Nov 15 '22 20:11

Luke Taylor


It turns out that this error was caused by calling oldBitmap.recycle() in the entryRemoved(..) method in my class overriding LruCache. As the bitmap might still be attached to the ImageView calling recycle() will cause trouble.

If I understand correctly: LruCache's cache size will be set in its constructor. When the number of items exceeds this size the objects will be eligible for garbage collection, which will happen when the bitmap is no longer associated with an ImageView.

A lot of examples and tutorials around the web suggest that recycle() should be called in entryRemoved(..), but from what I can see this is wrong.

like image 33
hanspeide Avatar answered Nov 15 '22 20:11

hanspeide