4

我正在尝试用 gif 制作一个 recyclerview。一切都完美显示,但 fresco 不缓存 gif。向下滚动回收器并再次向上滚动后,gif 将再次加载。我认为它们应该被缓存并更快地加载。以前我使用过ION library。加载速度更快,没有缓存问题。我不得不更改 lib,因为它在 gif 解码方面存在一些问题,在此处进行了描述。当前的解决方案如下所示:

//for default initial in application class 

Fresco.initialize(this);
//I have also tried to change DiskCacheConfig and ImagePipelineConfig params. 
//Without any positive result

//for recyclerview on onBindViewHolder    
GenericDraweeHierarchy hierarchy = holder.draweeView.getHierarchy();
Uri uri = Uri.parse(path);
hierarchy.setPlaceholderImage(R.drawable.img_bg);
Logger.e(check(uri) + " " + uri.toString());
DraweeController controller = Fresco.newDraweeControllerBuilder().setUri(uri)
            .setAutoPlayAnimations(true).build();
    holder.draweeView.setController(controller);

//for method which show cached uri images in imagepipeline
public static boolean check(Uri uri) {
    ImagePipeline imagePipeline = Fresco.getImagePipeline();
    return imagePipeline.isInBitmapMemoryCache(uri);
}
//... all the time log shows "false + gif url"

我没有看到任何关于不缓存动画图像的信息。有关于不支持的动画图像后处理的信息,但这就是全部。如何正确缓存 GIF?

编辑: 它看起来像壁画缓存动画,因为下面的方法为重新加载的 gif 返回 true。

public static boolean isImageDownloaded(Uri loadUri) {
    if (loadUri == null) {
        return false;
    }
    CacheKey cacheKey = DefaultCacheKeyFactory.getInstance()
            .getEncodedCacheKey(ImageRequest.fromUri(loadUri));
    return ImagePipelineFactory.getInstance().getMainDiskStorageCache().hasKey(cacheKey)
            || ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache()
                    .hasKey(cacheKey);
}
4

3 回答 3

1

为了让事情更清楚一点,Fresco 有 3 级缓存:

  • DiskCache - 以原始格式保存图像文件。(准确地说,如果在不完全支持 webp 图像的 Android 版本上,它们可能会在存储之前被转码为其他格式。)
  • EncodedMemoryCache - 原始编码格式的图像在内存中缓存。(图像保存为原始字节的字节数组,因为它们存储在磁盘上+一些额外的元数据。)
  • BitmapMemoryCache - 主要由 Android 位图组成的内存缓存。位图是解码后的图像,每个像素占用 32 位,这比编码时要多得多。

权衡显然是空间与时间。可用内存是有限的,如果图像不在位图缓存中,则必须再次对其进行解码。此外,如果它也不在编码内存缓存中,则必须从磁盘读取它,这也可能很慢。

现在回到动画图像。这是一个已知的限制。动画图像不会以其解码形式缓存,因为这会耗尽位图缓存(只需乘以 num_frames * width * height * 32bpp),并且单个动画图像可能会驱逐缓存中的所有其他图像。相反,它们是按需解码的,只有几帧接下来要显示的帧被保存在一个短暂的缓存中。

我们有一些改进动画的计划,尽管我无法提供任何时间估计。

于 2016-01-27T18:16:29.863 回答
0

Fresco,他们主要关注小尺寸的 gif。我尝试在 recycleview 中使用小尺寸的 gif,缓存效果很好。如果您使用高分辨率 gif,则它们需要大量内存消耗来进行解码和缓存。可能超过堆大小。所以它们是按需解码的,只有几帧(即将显示的)被缓存。

可以将 fresco 配置为在可用时立即显示第一帧(无需解码整个帧)并轻松缓存静态的第一帧。

        ImageDecodeOptionsBuilder b = new ImageDecodeOptionsBuilder();
        b.setForceStaticImage(true);
        ImageDecodeOptions imageDecodeOptions=new ImageDecodeOptions(b);
        ImageRequest request =  ImageRequestBuilder.newBuilderWithSource(animatedGifUri).setImageDecodeOptions(imageDecodeOptions).setLocalThumbnailPreviewsEnabled(true).build();
于 2016-07-07T04:44:42.540 回答
0

我遇到了同样的问题,Fresco 似乎正确缓存了 gif 图像,但实际上每次滚动 RecyclerView 或您正在使用的任何其他视图时都需要时间来解码和播放动画。但是,如果您使用没有动画的 gif 图像,则 gif 图像在滚动视图时不会“重新加载”。

因为我可以控制我的应用程序中显示的图像。我在我的服务器上创建了 2 个版本的 gif 图像,第一个没有动画显示在 RecyclerView/ListView 中,另一个显示在“媒体查看器”活动中,当用户单击列表中的一个项目时。

于 2016-01-27T14:56:59.647 回答