Glide 是一个图片加载库,跟它同类型的库还有 Picasso、Fresco、Universal-Image-Loader 等。
本文主要从以下几个角度来分析 Glide:
- 分析 Glide 到整体结构设计 (分层设计、缓存设计)。
- 分析 DataLoadProvider、ModelLoader、DataFetcher 的作用及它们之间的关系。
- 分析 LoadProvider 到作用。
Glide 框架的优点:
- 加载类型多样化:Glide 支持 Gif、WebP 等格式的图片。
- 生命周期的绑定:图片请求与页面生命周期绑定,避免内存泄漏。
- 使用简单(链式调用),且提供丰富的 Api 功能 (如: 图片裁剪等功能)。
- 高效的缓存策略:
1. 支持多种缓存策略 (Memory 和 Disk 图片缓存)。
2. 根据 ImageView 的大小来加载相应大小的图片尺寸。
3. 内存开销小,默认使用 RGB_565 格式 (3.x 版本)。
4. 使用 BitmapPool 进行 Bitmap 的复用。
本系列采用 Glide3.7.0 版本,从以下几个角度来进行分析。
注: 目前 Glide 版本已经更新到 4.11.0,但本系列我们仍采用 Glide3.7.0 版本进行分析,原因有两个:
(a) 3.7.0 版本代码相对比较简单。
(b) 与 3.7.0 版本相比,4.0+ 版本之后代码改动较大。
所以本着先易后难的原则,我们使用 Glide 3.7.0 来进行分析,对 Glide 整体有一个全面了解之后,再去分析 4.0+ 版本。
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'
Glide 框架结构如上图所示:
- Glide 框架主要分为两大流程:
1.1图片请求的构建流程
。
1.2图片缓存的获取流程
。- 图片请求构建流程内又分为四个模块:
2.1用户态的请求模块:
用户使用 Glide 进行链式调用的时候会生成一个用户态的 Request。
2.2真实的请求模块:
由于步骤2.1中会根据场景构建多种Request,因此在发起图片请求时需要进行收口,因此会使用用户态的 Request 构建一个真正的 GenericRequest 请求。
2.3Request 生命周期管理模块:
Glide 的一大特点是会将图片的请求和页面生命周期进行绑定,避免出现内存泄漏的风险,因此会有一个 Request 生命周期管理模块。
2.4Registry中心模块:
由于 Glide 支持加载多种类型的数据,因此在注册中心会预先注册所支持类型处理类的信息。- 图片缓存一共分为3大层,5小层:
3.1内存缓存(2小层):
弱引用缓存、LruCache。
3.2本地缓存(2小层):
本地 Result 缓存、本地 Source 缓存。
3.3Source 数据源(1小层):
网络获取、本地 AssetPath 获取、其它本地图片。
小结:
看到这里,只要知道以下三点就可以了。
- 知道 Glide 分为两大流程 (请求创建流程、缓存获取流程) 就可以了。
- 知道 Glide 缓存部分分为3大层,5小层就可以了。
- 可以将 Glide 的两大流程与网络请求进行类比。网络请求也分为两个流程:网络请求的构建流程、数据的接收和响应流程 (Glide的缓存获取流程)。
在 Glide 中,有几个比较重要的接口类,它们之间的关系如下图所示。
上图涉及的几个类含义如下:
DataLoadProvider:
提供特定类型的编/解码器的类,从它的抽象方法就可以看出。LoadProvider:
用于将ModelLoader
和ResourceTranscoder
进行关联 (相当于将编解码功能、数据获取功能、数据类型转换功能都聚合在一个 Provider 上,便于操作)。ModelLoader:
ModelLoader 是与支持的加载类型相匹配的,返回能够加载指定类型数据的 DataFetcher。ResourceTranscoder:
类型转换器 (如: 将 Resource转换成 Resource 类型)。 DataFetcher:
具体加载数据的类 (如: 从网络上加载图片数据)。Encoder:
用于将原始数据写入Disk缓存。ResoutceEncoder:
用于将 decoded 和 transformed 之后的资源写入 Disk 缓存。ResoutceDecoder:
用于将原始数据或者是Disk缓存数据进行解码,解析成可以使用的格式。
小结: 看到这里,需要了解如下信息。
- DataLoadProvider 内持有处理图片相关的编/解码器。
- LoadProvider 是一个聚合类,继承自 DataLoadProvider 接口,因此具备提供编解码器的能力,同时聚合了 ModelLoader 和 ResourceTranscoder。
- ModelLoader 会根据提供的加载类型返回一个相应的 DataFetcher。
在第三部分,我们分析了 DataLoadProvider、ModelLoader、DataFetcher 之间的关系,知道了 LoadProvider 是一个聚合类,下面我们来具体分析一下。
LoadProvider 有两个子类:FixLoadProvider
、ChildLoadProvider
。
FixLoadProvider
public class FixedLoadProvider<A, T, Z, R> implements LoadProvider<A, T, Z, R> {
private final ModelLoader<A, T> modelLoader;
private final ResourceTranscoder<Z, R> transcoder;
private final DataLoadProvider<T, Z> dataLoadProvider;
public FixedLoadProvider(ModelLoader<A, T> modelLoader, ResourceTranscoder<Z, R> transcoder,
DataLoadProvider<T, Z> dataLoadProvider) {
this.modelLoader = modelLoader;
this.transcoder = transcoder;
this.dataLoadProvider = dataLoadProvider;
}
}
小结:
FixLoadProvider 是一个聚合类,持有 ModelLoader、ResourceTranscoder、DataLoadProvider 对象的引用,具备提供 DataFetcher、图片编/解码器、图片转码 的功能。
public class ChildLoadProvider<A, T, Z, R> implements LoadProvider<A, T, Z, R>, Cloneable {
private final LoadProvider<A, T, Z, R> parent;
private ResourceDecoder<File, Z> cacheDecoder;
public ChildLoadProvider(LoadProvider<A, T, Z, R> parent) {
this.parent = parent;
}
@Override
public ModelLoader<A, T> getModelLoader() {
return parent.getModelLoader();
}
public void setCacheDecoder(ResourceDecoder<File, Z> cacheDecoder) {
this.cacheDecoder = cacheDecoder;
}
@Override
public ResourceDecoder<File, Z> getCacheDecoder() {
if (cacheDecoder != null) {
return cacheDecoder;
} else {
return parent.getCacheDecoder();
}
}
}
小结:
ChildLoadProvider 内持有一个 LoadProvider 引用,相关的操作都是通过这个 LoadProvider 引用进行操作,同时提供了对 编解码器 进行赋值的 Api。
FixLoadProvider 和 ChildLoadProvider 构成了一个装饰者模式。其中 ChildLoadProvider 是 Decorator 角色,他提供设置 编/解码器的功能。
为什么要这么设计?
默认情况下 FixLoadProvider 是自动创建的,不支持用户设置自定义的
ResourceTranscoder
以及编/解码器
。而通过装饰者模式可以对原有的 FixLoadProvider 功能进行增强,使之具备这个功能。
下一篇文章我们先来分析一下 《Glide 注册模块分析》 ,这有助于分析 Glide加载流程。