Fresco后处理器:java.lang.RuntimeException: 画布:尝试使用已回收的位图

3
12-21 11:01:14.045: E/AndroidRuntime(6819): java.lang.RuntimeException: Canvas:尝试使用已回收的位图 android.graphics.Bitmap@4180103 12-21 11:01:14.045: E/AndroidRuntime(6819): 在 android.graphics.Canvas.throwIfCannotDraw(Canvas.java:1084) 12-21 11:01:14.045: E/AndroidRuntime(6819): 中抛出 at android.view.GLES20Canvas.drawBitmap(GLES20Canvas.java:844) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.graphics.drawable.BitmapDrawable.draw(BitmapDrawable.java:490) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.widget.ImageView.onDraw(ImageView.java:1037) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.view.View.draw(View.java:14465) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.view.View.getDisplayList(View.java:13362) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.view.View.getDisplayList(View.java:13404) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.view.View.draw(View.java:14182) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.view.ViewGroup.drawChild(ViewGroup.java:3103) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.view.ViewGroup.dispatchDraw(ViewGroup.java:2940) 12-21 11:01:14.045: E/AndroidRuntime(6819): at android.widget.AbsListView.dispatchDraw(AbsListView.java:2458)
我创建了一个新类,并使其扩展了BasePostprocessor,但在它运行时,样本会抛出上述异常; 我只使用 imagepipeline 下载图片,不使用 simpledraweeview
com.facebook.imagepipeline.request.ImageRequestBuilder requestBuilder=   com.facebook.imagepipeline.request.ImageRequestBuilder
.newBuilderWithSource(uri);

if (imageRequest.getTargetWidth() > 0 && imageRequest.getTargetHeight()  > 0) {
    requestBuilder.setResizeOptions(new com.facebook.imagepipeline.common.ResizeOptions(imageRequest
            .getTargetWidth(), imageRequest.getTargetHeight()));
}

requestBuilder.setAutoRotateEnabled(true);
requestBuilder.setPostprocessor(new FPostProcessor(getImageConfig()));
public class FPostProcessor extends BasePostprocessor{
private FImageConfig mImageConfig;

public FPostProcessor(FImageConfig imageConfig){
    mImageConfig = imageConfig;
}
/*
@Override
public CloseableReference<Bitmap> process(Bitmap sourceBitmap,    PlatformBitmapFactory bitmapFactory) {
return super.process(sourceBitmap, bitmapFactory);
}*/
}

这个问题有什么解决方法吗? - surlac
这个问题没有现成的解决方案,我必须创建一个扩展DrawweeView的自定义视图。 - Hilda
1个回答

0

我认为这与后处理器无关。如果您没有使用Drawee,而是直接使用imagepipeline,则需要非常小心地处理图像。您应该阅读有关如何直接使用imagepipeline的文档。

我怀疑您从管道中获取了ClsoeableReference<CloseableImage>,然后只取出其中的位图并忘记了ClsoeableReference。这是错误的做法。一旦ClsoeableReference超出范围,它将变得容易受到垃圾回收的影响,当GC发生时,底层位图可能会被回收。即使您使用提供位图的BaseBitmapDataSubscriber也是如此。这在文档中也有详细介绍。

您经历这种情况的最可能原因是使用后处理器而不是不使用后处理器的情况下,因为在前者的情况下,位图缓存可能会保持位图的活动状态。但是,由于您的后处理器未启用缓存,因此不会发生这种情况。

换句话说,Pipeline返回一个包装着Bitmap B的CloseableImage I的CloseableReference<CloseableImage> R1。还有一个CloseableReference R2包装了相同的CloseableImage I,被保存在位图缓存中,直到缓存决定清除该图片为止。由于缓存和您都有对该图片的引用,因此其引用计数为2。即使您不遵守Fresco API,让您的CloseableReference R1被垃圾回收,引用计数也只会降至1,因为缓存仍然将其保存在内存中。但是,您不应该依赖于此。这是没有后处理器的情况。
如果您指定了一个后处理器,会发生一些略有不同的事情。Pipeline现在将原始的CloseableImage I1Bitmap B1缓存起来,但会返回一个经过后处理的CloseableImage I2Bitmap B2。由于您的后处理器没有启用缓存,您将成为对I2唯一的持有者,这次如果让它被垃圾回收,您将得到一个已回收的位图,因为没有缓存来隐藏这个问题。
请明确一点,正确的解决方案不是启用后处理器缓存!正确的解决方案是正确处理pipeline返回的CloseableReference,如文档中所述。
如果您没有提供使用pipeline的实际代码,我无法确定,但这很可能是发生的情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接