fresco Postprocessor:java.lang.RuntimeException: Canvas: 尝试使用回收位图

fresco Postprocessor:java.lang.RuntimeException: Canvas: trying to use a recycled bitmap

12-21 11:01:14.045: E/AndroidRuntime(6819): java.lang.RuntimeException: Canvas: trying to use a recycled bitmap android.graphics.Bitmap@4180103 12-21 11:01:14.045: E/AndroidRuntime(6819): at 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)

我构建了一个新的 class 并扩展了 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);
}*/
}

我认为这与后处理器无关。如果你没有使用 Drawee,而是直接使用图像管道,你需要非常小心地处理图像。您应该阅读有关 how to use the imagepipeline directly.

的文档

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

中也对此进行了详细介绍

你使用后处理器而不是没有它时遇到这种情况的最可能原因是因为在前一种情况下,位图缓存可能会使你的位图保持活动状态。对于您的后处理器,这不会发生,因为它没有启用缓存。

换句话说,管道 return 是一个用 Bitmap B 包装 CloseableImage IClsoeableReference<CloseableImage> R1。将有另一个 CloseableReference R2 包装保存在位图缓存中的相同 CloseableImage I ,直到稍后缓存决定驱逐该图像。由于缓存和您都有对该图像的引用,因此它的引用计数为 2。即使您不遵守 Fresco API 并且让您的 CloseableReference R1 被垃圾收集,引用计数也只会下降到 1 因为缓存仍然在内存中。但是,您不应该依赖它。那是 没有 后处理器。

如果您指定后处理器,会发生一些稍微不同的事情。管道现在将使用 Bitmap B1 缓存原始 CloseableImage I1,但将 return 一个 new 后处理 CloseableImage I2Bitmap B2。由于你的后处理器没有启用缓存,你将成为 唯一 引用 I2 的持有者,这次如果你让它被垃圾收集,你将留下回收的位图,因为没有缓存来隐藏问题。

明确一点,正确的解决方案是不启用后处理器缓存!正确的解决方案是正确处理管道 CloseableReference returned,如文档中所述。

在没有提供您如何使用管道的实际代码的情况下,我无法确定,但这很可能会发生。