【问题标题】:Caching gifs in fresco在 fresco 中缓存 gif
【发布时间】:2016-05-03 01:33:09
【问题描述】:

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

//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?

编辑: 它看起来像 fresco 缓存动画,因为下面的方法为重新加载的 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);
}

【问题讨论】:

    标签: android caching android-recyclerview gif fresco


    【解决方案1】:

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

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

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

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

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

    【讨论】:

    • 我只是想知道如何缓存和显示 gif 的第一帧
    • 您可能应该在原始问题中澄清您只对第一帧感兴趣。
    【解决方案2】:

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

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

    【讨论】:

    • 这不是令人满意的解决方案。我必须显示自动启动的 gif 网格。当您查看 GIF 键盘应用程序时,您会看到带有自动启动动画的 gif 列表/网格。它以可接受的缓存行为平滑滚动。他们的解决方案应该是合适的。
    • 应该是合适的,但遗憾的是我无法弄清楚它们是如何实现高效缓存和平滑滚动的。
    • 我使用 fresco 加载 gif 而不是动画。滚动时,我仍然遇到问题
    • @McHaimech 你有没有办法解决 gif 的 2 个版本?
    • setAutoPlayAnimations(false) 最好不要解码 GIF。可能是第一帧缩略图被缓存了。这是真的@AllenVork
    【解决方案3】:

    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();
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-02-12
      • 1970-01-01
      • 2016-12-17
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 2019-06-30
      • 1970-01-01
      相关资源
      最近更新 更多