本文基于 Glide从磁盘加载图片资源的流程,介绍了 Glide 是如何根据 ByteBuffer 解析出 Gif 动图的,并如何实现 Gif 动画循环♻️。
// 假设通过这种方式下载并注入 Gif 图片
Glide.with(this)
.load("https://example.com/foo.gif")
.into(binding.ivThumbnail)
前情提要:
前一篇文章 介绍了 Glide 如何从网络中下载图片,缓存到磁盘,并从磁盘缓存中加载得到 File,解析得到 ByteBuffer。DataCacheGenerator#startNext 中从磁盘中加载得到 File,并使用 ByteBufferFetcher 将 File 加载成 ByteBuffer,然后一连串通知走到 DecodeJob#onDataFetcherReady,最后 DecodeJob#decodeFromData 解析得到 Resource 对象。
ByteBuffer 解析得到 GifDrawableResource
现在我们就看看 ByteBuffer
是如何解析得到 Resource<GifDrawable>
的。
#decodeFromData -> DecodeJob#decodeFromFetcher,主要过程就两步,首先创建 LoadPath,然后用 LoadPath#load 加载得到 Resource。LoadPath 其实又是用内部的 DecodePath 列表来对 ByteBuffer 解码的,DecodePath#decodeResourceWithList 中会从其内部 decoders 列表中找到可以 handles ByteBuffer 和 option 的解码器。所以重点关注 DecodePath 是如何得到 decoders 列表的。
- LoadPath 的创建,还是用到 Glide 初始时配置的 Registry, Registry#getLoadPath 中,先找到 DecodePath 列表,再用其创建 LoadPath。
// DecodeJob
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
throws GlideException {
// ❤️ LoadPath 的创建
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
return runLoadPath(data, dataSource, path);
}
-
生成 DecodePath 列表,需要用到 dataClass, resourceClass, transcodeClass,在我们的使用实例中 load(String).into(ImageView),对应的三个类为 ByteBuffer.class,Object.class,Drawable.class。
-
1️⃣首先从 ResourceDecodeRegistry 中,根据 dataClass,resourceClass 找到所有支持的 registeredResourceClass 列表,这个支持是指,注册是使用了
<? super dataClass, ? extends resurceClass>
,确保能解析成功;2️⃣接着,进入一层 for 循环,从 TranscoderRegistry 中,根据 registeredResourceClass 列表中每一项和 transcodeClass,找到所有支持的 registeredTranscodeClass 列表,这里的支持是指,注册时使用了<? super resurceClass, ? extends transcodeClass>
;3️⃣最后,在第二层 for 循环中,用 dataClass、registeredResourceClass、registeredTranscodeClass 创建 DecodePath 列表。
// Registry
private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
@NonNull Class<Data> dataClass,
@NonNull Class<TResource> resourceClass,
@NonNull Class<Transcode> transcodeClass) {
Lis