chrisbanes / Android-BitmapCache

Android-BitmapCache is a specialised cache, for use with Android Bitmap objects.
834 stars 224 forks source link

TransitionDrawable and Recycled Bitmap Exception #36

Open mandrachek opened 11 years ago

mandrachek commented 11 years ago

I've got a recycled bitmap issue cropping up when using a TransitionDrawable. I'm seeing this pretty consistently on an HTC Desire HD running 2.3.3, and sporadically on other devices. I'm using version 2.3 and the cache is configured for memory only.

I am able to get work around the issue by manually calling cbd.setBeingUsed(true); after pulling the bitmap from the cache, like so (and yes, mImageView is an instance of CacheableImageView):

private void animate() {
    if (mImageView == null) { Log.w(TAG,"Null imageview?"); return; }
    if (this.isDetached()) { Log.w(TAG,"Attempting animation on detached fragment."); return; }

    int imageIndex = getNextIndex();
    currentIndex = imageIndex;
    String index = String.valueOf(images[imageIndex]);

    CacheableBitmapDrawable cbd = null;
    if (mCache.contains(index)) {
        cbd = mCache.get(index);
    }
    if (cbd == null || !cbd.isBitmapValid()) {
        cbd = mCache.put(index, BitmapFactory.decodeResource(getResources(), images[imageIndex]));
    }
    // without this, I get sporadic recycled bitmap errors!
    cbd.setBeingUsed(true);

    Drawable[] drawables = new Drawable[2];
    drawables[0] = mImageView.getDrawable();
    drawables[1] = cbd;
    TransitionDrawable transitionDrawable = new TransitionDrawable(drawables);
    transitionDrawable.setCrossFadeEnabled(true);
    mImageView.setImageDrawable(transitionDrawable);
    transitionDrawable.startTransition(2000);
}

The stack trace is:

java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@40644e28 at 
android.graphics.Canvas.throwIfRecycled(Canvas.java:973) at 
android.graphics.Canvas.drawBitmap(Canvas.java:1062) at
android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:325) at
uk.co.senab.bitmapcache.CacheableBitmapDrawable.draw(CacheableBitmapDrawable.java:77) at
android.graphics.drawable.TransitionDrawable.draw(TransitionDrawable.java:204) at 
android.graphics.drawable.TransitionDrawable.draw(TransitionDrawable.java:196) at 
android.graphics.drawable.TransitionDrawable.draw(TransitionDrawable.java:196) at 
android.widget.ImageView.onDraw(ImageView.java:935) at 
android.view.View.draw(View.java:6971) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1710) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1708) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.View.draw(View.java:6974) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1710) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1708) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.View.draw(View.java:6974) at 
android.support.v4.view.ViewPager.draw(ViewPager.java:2157) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1710) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1708) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.View.draw(View.java:6974) at 
android.widget.FrameLayout.draw(FrameLayout.java:357) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1710) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1708) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.ViewGroup.drawChild(ViewGroup.java:1708) at 
android.view.ViewGroup.dispatchDraw(ViewGroup.java:1437) at 
android.view.View.draw(View.java:6974) at 
android.widget.FrameLayout.draw(FrameLayout.java:357) at 
com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1929) at 
android.view.ViewRoot.draw(ViewRoot.java:1590) at 
android.view.ViewRoot.performTraversals(ViewRoot.java:1290) at 
android.view.ViewRoot.handleMessage(ViewRoot.java:1939) at 
android.os.Handler.dispatchMessage(Handler.java:99) at 
android.os.Looper.loop(Looper.java:143) at 
android.app.ActivityThread.main(ActivityThread.java:4196) at 
java.lang.reflect.Method.invokeNative(Native Method) at 
java.lang.reflect.Method.invoke(Method.java:507) at 
com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) at 
com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) at
dalvik.system.NativeStart.main(Native Method)
mandrachek commented 11 years ago

Ugh. So with cbd.setBeingUsed(true), it looks like on some devices, I wind up with out of memory errors. :(

shawnthye commented 11 years ago

You can try using FileDescriptor to decode from DiskCache. keep decodeStream when putting CacheableBitmapDrawable to MemoryCache.

I loaded 300 high quality images in grid view. sorry my english is bad.