一、概述
1.1 背景
Glide 是一个图片加载库,跟它同类型的库还有 Picasso、Fresco、Universal-Image-Loader 等。基于 Glide 优秀的缓存管理策略和生命周期关联的特点,目前市面上对 Glide 的使用非常广,因此我们有必要深入研究下 Glide 相关的实现原理,便于更好的使用它。
在 Glide系列(一) — Glide 框架结构浅析 一文中,我们介绍了 Glide 框架的整体结构,同时也介绍 Glide 中的几个关键概念,其中涉及到 DataLoaderProvider
、ModelLoader
和 DataFetcher
之间的关系。本文我们重点来分析一下 DataLoaderProvider
及与其相关的 Encoder/Decoder
部分。
Glide 版本:
Glide 3.7.0
Github 地址:https://github.com/bumptech/glide/tree/v3.7.0
Gradle 依赖:implementation 'com.github.bumptech.glide:glide:3.7.0'
1.2 系列文章
- Glide系列(一) — Glide 框架结构浅析
- Glide系列(二) — DataLoadProvider 及与 Encoder&Decoder 的关系
- Glide系列(三) — LoadProvider、ModelLoader、DataFetcher 和 ResourceTranscoder 关系
- Glide系列(四) — Glide 缓存流程分析
- DiskLruCache 源码分析
二、准备知识
在接下去分析之前,我们先要对 Glide 框架的功能有一些基本认识:
- Glide 框架支持加载静态图
(Bitmap)
、动态图(Gif)
、视频(视频首帧,也是图Bitmap
)。- Glide 框架接收 DataFetcher 返回的数据类型为
InputStream
、FileDescriptor
。- Glide 支持加载的资源路径类型 (即
RequestManager.load(T)
中的T类型) 有:int/Integer、String、File、Uri、URL、byte[]
6种。
本文我们将具体分析 DataLoadProvider 部分,主要从下面2部分展开:
- DataLoadProvider 注册及使用。
- Encoder、Decoder 和 DataLoadProvider 的关系。
三、DataLoadProvider
3.1 DataLoadProvider<T, Z> 泛型类型与内部编码器泛型的关系
DataLoadProvider 的主要作用是对外提供相应的编/解码器。根据 Glide系列(一) — Glide 框架结构浅析 中的介绍,当我们知道了 DataLoadProvider<T, Z> 泛型类型时,也就知道了对应编/解码器处理参数的类型。下面举个例子来说明:
以 StreamBitmapDataLoadProvider<InputStream, Bitmap>
为例:
代码如下:
public class StreamBitmapDataLoadProvider implements DataLoadProvider<InputStream, Bitmap> {
// 解码 ResultCache、SourceCache 缓存
public ResourceDecoder<File, Bitmap> getCacheDecoder() {
return cacheDecoder;
}
// 解码 Source 缓存(第5层缓存,即数据源)
public ResourceDecoder<InputStream, Bitmap> getSourceDecoder() {
return decoder;
}
// 对从 Source 缓存(第5层缓存,即数据源) 获取的数据进行编码
public Encoder<InputStream> getSourceEncoder() {
return sourceEncoder;
}
// 对经过 transform 之后的数据进行编码
public ResourceEncoder<Bitmap> getEncoder() {
return encoder;
}
}
小结:
DataFetcher
是用于加载第5层Source缓存
的数据 (如网络、Asset目录),并将数据提供给 DataLoadProvider 的 SourceDecoder 进行解码,DataFetcher
对外提供的数据格式有Stream、FileDescriptor
两种,这里 StreamBitmapDataLoadProvider 支持接收DataFetcher
返回 Stream 类型的数据。- DataLoadProvider 中解码器:
CacheDecoder:
解码ResultCache、SourceCache
缓存,且这两层的缓存由Glide产生,所以接收File类型的输入,并返回Bitmap 类型的输出。SourceDecoder:
对第5层Source缓存(数据源)
进行解码,数据源是由DataFetcher
提供的 Stream 类型。SourceEncoder:
将第5层Source缓存(数据源)
缓存到第4层SourceCache缓存
。Encoder (CacheEncoder):
将第5层的Source缓存
数据通过SourceDecoder
解码(生成 Resource),再对解码后的数据使用transform
操作生成新的 Resource,然后将 新的 Resource 数据缓存到第3层ResultCache缓存
。
DataLoadProvider 中几种 编/解码器
的使用场景如下图所示:
小结:
到这里我们只要知道 DataLoadProvider<T, Z> 不同的泛型类型会影响到内部的编/解码类的接收和返回参数类型就可以了。
在分析完 DataLoadProvider
和其内部 编/解码器
的作用及其使用场景后,接下来我们看下具体有哪些 DataLoadProvider 实例,他们是怎么在 Glide 中查找的,都有些什么作用。
3.2 DataLoadProviderRegistry 注册表
首先,DataLoadProvider 是通过注册机制来维护,注册表为 DataLoadProviderRegistry
,其数据结构为一个 HashMap,用来映射 接收参数和返回参数
与 DataLoadProvider
之间的关系。
下面为 DataLoadProviderRegistry 的代码部分,展示了其数据结构和注册部分的逻辑。
// DataLoadProviderRegistry.class
private final Map<MultiClassKey, DataLoadProvider<?, ?>> providers =
new HashMap<MultiClassKey, DataLoadProvider<?, ?>>();
public <T, Z> void register(Class<T> dataClass,
Class<Z> resourceClass, DataLoadProvider<T, Z> provider) {
// 将 dataClass 和 resourceClass 封装成一个 Key 值。
providers.put(new MultiClassKey(dataClass, resourceClass), provider);
}
小结:
- DataLoadProviderRegistry 注册表的数据结构是一个 HashMap。
- 这个 HashMap 中的 key 是由
dataClass 和 resourceClass
两部分的Class类型组成的。而这两部分其实分别对应了 DataLoadProvider<T, Z> 中的两个泛型参数(T、Z)。
3.3 DataLoadProvider 的注册
上面介绍了 DataLoadProviderRegistry 的数据结构,接下来我们来看下具体的注册场景,看看有哪些 DataLoadProvider 类型,以及他们之间的关系如何?
// Glide.class
// DataLoadProvider 注册中心
private final DataLoadProviderRegistry dataLoadProviderRegistry;
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool,
Context context, DecodeFormat decodeFormat) {
// DataLoadProvider 的注册中心。
dataLoadProviderRegistry = new DataLoadProviderRegistry();
// 1.处理静态图的DataLoadProvider:输入为InputStream类型,输出为Bitmap类型。
StreamBitmapDataLoadProvider streamBitmapLoadProvider =
new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);
// 2.处理静态图的DataLoadProvider:输入为Fd类型,输出为Bitmap类型。
FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider =
new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat);
dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider);
// 3.支持处理静态图和视频:是一种包装类型,包含前面两种。
ImageVideoDataLoadProvider imageVideoDataLoadProvider =
new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);
// 4.处理Gif的DataLoadProvider:输入为InputStream类型,输出为GifDrawable类型。
GifDrawableLoadProvider gifDrawableLoadProvider =
new GifDrawableLoadProvider(context, bitmapPool);
dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider);
// 大杂烩,支持处理静态图、视频和Gif,包含前三种。
dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider,
gifDrawableLoadProvider, bitmapPool));
// 6.这里是支持使用Glide直接下载图片文件。
dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider());
}
DataLoadProvider 类型的罗列:
dataClass | resourceClass | DataLoadProvider | 说明 |
---|---|---|---|
InputStream | Bitmap | StreamBitmapDataLoadProvider | 处理Stream类型的数据,转成Bitmap。 |
ParcelFileDescriptor | Bitmap | FileDescriptorBitmapDataLoadProvider | 处理fd类型的数据,转成Bitmap。 |
ImageVideoWrapper | ImageVideoWrapper | ImageVideoDataLoadProvider | 处理Stream&fd类型的数据,转成Bitmap。 |
InputStream | GifDrawable | GifDrawableLoadProvider | 处理Stream类型的数据,转成 GifDrawable。 |
ImageVideoWrapper | GifBitmapWrapper | ImageVideoGifDrawableLoadProvider | 处理Stream&fd类型的数据,转成Bitmap或者Gif。 |
InputStream | File | StreamFileDataLoadProvider | 用于直接使用Glide下载图片文件。 |
DataLoadProvider 之间的关系图:
为什么要设计这么多的包装类型?
实现 Glide 对图片的智能加载。我们在使用 Glide 过程中,如果没有明确使用
asBitmap
、asGif
方法,那么Glide是不知道我们加载的文件类型,因此就需要考虑所有的情况。使用 DataLoadProvider 包装类时,内部的编解码器也会根据包装类的类型进行编解码器的包装,类似于责任链的调用方式。
小结:
我们在前面第二部分的准备知识里讲过,Glide 可以加载三种类型的数据:静态图、Gif图、视频(首帧),但严格意义上来说,视频首帧其实也可以归类到前面的静态图类型。结合上面的表格,我们可以得到以下结论。
- Glide 支持加载两种图:静态图、动态图。
- dataClass 输入类型只有两种:
InputStream、ParcelFileDescriptor
,这与我们前面介绍的 DataFetcher 返回的数据类型保持一致。- dataClass 输入类型为 ImageVideoWrapper的,它里面包装了
InputStream 和 ParcelFileDescriptor
。- resourceClass 返回的类型只有3种:Bitmap、GifDrawable、File,其中前两种与图片显示有关,最后一种是下载图片文件。
- resourceClass 返回的类型为 GifBitmapWrapper 的,它里面包装了 Bitmap 和 GifDrawable 两种类型。
3.4 DataLoadProvider 的获取
介绍完了 DataLoadProvider 的注册之后,下面我们看下 DataLoadProvider 的获取方法。
// Glide.class
<T, Z> DataLoadProvider<T, Z> buildDataProvider(Class<T> dataClass, Class<Z> decodedClass) {
return dataLoadProviderRegistry.get(dataClass, decodedClass);
}
// DataLoadProviderRegistry.class
public <T, Z> DataLoadProvider<T, Z> get(Class<T> dataClass, Class<Z> resourceClass) {
DataLoadProvider<?, ?> result;
// GET_KEY 是一个单例,对单例进行赋值时需要上锁。
synchronized (GET_KEY) {
GET_KEY.set(dataClass, resourceClass);
result = providers.get(GET_KEY);
}
if (result == null) {
result = EmptyDataLoadProvider.get();
}
return (DataLoadProvider<T, Z>) result;
}
小结:
在其它地方调用
Glide.buildDataProvider()
方法,通过dataClass、resourceClass
构建的 MultiClassKey 来从注册表里获取匹配的 DataLoadProvider。
3.5 示例代码
下面是调用 Glide.buildDataProvider()
的场景。
// DrawableTypeRequest.class
DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
super(context, modelClass,
// 这里传入的 resourceClass 是 GifBitmapWrapper 类型。
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
}
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader,
Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
// 省略代码
// 此处dataClass=ImageVideoWrapper,且resourceClass=GifBitmapWrapper,
// 所以返回的是ImageVideoGifDrawableLoadProvider。
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider =
glide.buildDataProvider(ImageVideoWrapper.class, resourceClass);
// 省略代码
// 然后统一包装到FixedLoadProvider中。
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
小结: 熟悉下面几种请求类型对应的 DataLoadProvider。
请求类型 | dataClass | resourceClass | DataLoadProvider |
---|---|---|---|
BitmapTypeRequest | ImageVideoWrapper | ImageVideoWrapper | ImageVideoDataLoadProvider |
GifTypeRequest | InputStream | GifDrawable | GifDrawableLoadProvider |
DrawableTypeRequest | ImageVideoWrapper | GifBitmapWrapper | ImageVideoGifDrawableLoadProvider |
GenericTranscodeRequest | InputStream | File | StreamFileDataLoadProvider |
到这里,我们就分析完了 DataLoadProvider 部分,接下来我们再分析一下 DataLoadProvider 中的编解码,以及他们与 DataLoadProvider 实现类的对应关系。
四、Encoder & ResourceEncoder
4.1 Encoder 的类型介绍
关于 Encoder & ResourceEncoder 的所有类型如下图所示:
ImageVideoWrapperEncoder 类型关系图:
Encoder 类型 | 主要功能 |
---|---|
NullEncoder | 空实现 |
StreamEncoder | 将 InputStream 写入文件。 |
ImageVideoWrapperEncoder | 包含了StreamEncoder 和 FileDescriptorEncoder,是一个包装类,用于判断执行哪种类型的Encoder进行文件保存。 |
BitmapEncoder | 将 Bitmap 保存为文件 |
GifResourceEncoder | 将 GifDrawable 保存为文件 |
GifBitmapWrapperResourceEncoder | 包含有 BitmapEncoder 和 GifEncoder,是一个包装类,用于判断执行哪种类型的Encoder进行文件保存。 |
小结:
- Encoder 分两种类型,一种是直接继承自 Encoder,另一种继承自 ResourceEncoder。
- 继承自 Encoder 的实现类,其
encode()
方法接收任意类型的参数,一般作为 DataLoadProvider 的 SourceEncoder 参数。 - 继承自 ResourceEncoder 的实现类,其
encode()
方法中接收 Resource 类型的参数,一般作为 DataLoadProvider 的 CacheEncoder 参数。 - ImageVideoWrapperEncoder 是一个包装类型,里面包含有StreamEncoder 和 FileDescriptorEncoder 。
- GifBitmapWrapperResourceEncoder 是一个包装类型,里面包含有 BitmapEncoder(实际为 ImageVideoWrapperEncoder 类型) 和 GifEncoder。
- 包装类型的 Encoder 都是为了通过条件判断执行对应的
encode
逻辑。
4.2 Encoder 与 DataLoadProvider 的关系
下图为 DataLoadProvider 与 编码类型的关联关系。
DataLoadProvider 类型 | SourceEncoder (Encoder) | CacheEncoder (ResourceEncoder) |
---|---|---|
StreamBitmapDataLoadProvider | StreamEncoder | BitmapEncoder |
FileDescriptorBitmapDataLoadProvider | NullEncoder | BitmapEncoder |
ImageVideoDataLoadProvider | ImageVideoWrapperEncoder | BitmapEncoder |
GifDrawableLoadProvider | StreamEncoder | GifResourceEncoder |
ImageVideoGifDrawableLoadProvider | ImageVideoWrapperEncoder | GifBitmapWrapperResourceEncoder |
StreamFileDataLoadProvider(在上图中没有体现) | StreamEncoder | / |
五、ResourceDecoder
5.1 ResourceDecoder 的类型介绍
关于 ResourceDecoder 的所有类型如下图所示:
Decoder 类型 | 主要功能 |
---|---|
FileDecoder | 返回一个包含File的 FileResource 对象 |
FileDescriptorBitmapDecoder | 将一个fd指向的文件转换为Resource |
FileToStreamDecoder | 将输入的 File 类型转换为 Stream 传递给下一个Decoder |
GifResourceDecoder | 将输入数据转换为一个GifDrawableResource对象 |
GifBitmapWrapperResourceDecoder | 包含有 BitmapDecoder 和 GifDecoder,是一个包装类,用于判断执行哪种类型的Decoder进行解码。 |
StreamBitmapDecoder | 将InputStream的输入转化为Bitmap |
ImageVideoBitmapDecoder | 包含了StreamDecoder 和 FileDescriptoDecoder,是一个包装类,用于判断执行哪种类型的Decoder进行解码。 |
GifBitmapWrapperStreamResourceDecoder | 将输入的 InputStream 类型转换为 ImageVideoWrapper 传递给下一个Decoder |
小结:
- Decoder 最基础的解码器:
FileDescriptorBitmapDecoder 、GifResourceDecoder 、StreamBitmapDecoder
,解析出可用的数据类型。 - Decoder 输入类型转换器:
FileToStreamDecoder(File->Stream) 、GifBitmapWrapperStreamResourceDecoder
,即将输入的参数类型转换为另一种参数类型。 - ImageVideoBitmapDecoder 是一个包装类型,里面包含有StreamDecoder 和 FileDescriptorDecoder 。
- GifBitmapWrapperResourceDecoder 是一个包装类型,里面包含有 BitmapDecoder(实际为 ImageVideoBitmapDecoder 类型) 和 GifDecoder。
- 包装类型的 Decoder 都是为了通过条件判断执行对应的
decode
逻辑。
5.2 ResourceDecoder 与 DataLoadProvider 的关系
下图为 DataLoadProvider 与 解码码类型的关联关系。
DataLoadProvider 类型 | SourceDecoder | CacheDecoder |
---|---|---|
StreamBitmapDataLoadProvider | StreamBitmapDecoder | FileToStreamDecoder -> StreamBitmapDecoder |
FileDescriptorBitmapDataLoadProvider | FileDescriptorBitmapDecoder | FileToStreamDecoder -> StreamBitmapDecoder |
ImageVideoDataLoadProvider | ImageVideoBitmapDecoder | FileToStreamDecoder -> StreamBitmapDecoder |
GifDrawableLoadProvider | GifResourceDecoder | FileToStreamDecoder -> GifResourceDecoder |
ImageVideoGifDrawableLoadProvider | GifBitmapWrapperResourceDecoder | FileToStreamDecoder -> GifBitmapWrapperStreamResourceDecoder -> GifBitmapWrapperResourceDecoder |
StreamFileDataLoadProvider(在上图中没有体现) | / | FileDecoder |
小结:
- 图中的
GifBitmapWrapperResourceDecoder
解码器内的逻辑全部只执行 SourceDecoder 部分 (即蓝色部分的流程),不执行 CacheDecoder 部分的逻辑。 - 图中深绿色部分代表DataLoadProvider 类型。其用虚线引入解码类型的节点,表示下面的 SourceDecoder 和 CacheDecoder 是该 DataLoadProvider 内的两种解码器。
六、总结
- 了解 DataLoadProvider<T, Z> 泛型类型与内部编码器的关系。
- 了解编/解码器在缓存的哪个阶段使用 (看上面的图)。
- 了解 DataLoadProvider 注册表的数据结构 (HashMap),注册的 DataLoadProvider 类型。
- 了解注册的几个 DataLoadProvider 的包含关系 (看上面的图)。
- 了解不同的 Request 与各组 DataLoadProvider 的对应关系 (看上面的表格)。
- 了解 Encoder 的种类及其各自的作用 (看上面的表格)。
- 了解不同 Encoder 与 DataLoadProvider 的对应关系 (看上面的图)。
- 了解 Decoder 的种类及其各自的作用 (看上面的表格)。
- 了解不同 Decoder 与 DataLoadProvider 的对应关系 (看上面的图)。