Glide 源码阅读笔记(三)
在第一篇文章中我简单介绍了 Glide 实例的创建过程,重点介绍了 Glide 的内存缓存实现和磁盘的缓存实现:Glide 源码阅读笔记(一)
在第二篇文章中介绍了 Glide 对生命周期的管理: Glide 源码阅读笔记(二)
今天我们继续今天的内容。
源码阅读基于 Glide 4.16.0 版本
Reqeust 和 RequestCoordinator
Request 比较好理解,它就是一个图片加载的任务。RequestCoordinator 它也是继承于 Request,它是用来协调它内部的多个 Request,这么说比较抽象。我这里简单举一个例子。我们可以在使用 Glide 时,添加一个异常时请求的任务,当主任务加载失败时 Glide 就会去加载这个异常时请求的任务。例如以下代码:
Kotlin
val errorRequestBuilder = Glide.with(this)
.load("https://www.tans.com/error.png")
Glide.with(this)
.load("https://upload-images.jianshu.io/upload_images/5809200-a99419bb94924e6d.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240")
.error(errorRequestBuilder)
.into(findViewById<ImageView>(R.id.my_iv))
其中如何协调主 Request 与错误相关的 Request,就是 ErrorRequestCoordinator 的工作,它的工作原理非常简单,首先触发主 Request,当它请求失败时再去加载异常的 Request。类似原理的还有 ThumbnailRequestCoordinator,它是协调缩略图加载的 RequestCoordinator。后面的代码分析中我们都能看到他们。通过 RequestCoordinator 可以把单个 Request 构建成一个 Request 的请求树,可以用这个请求树来执行复杂的请求逻辑。
我们在使用 Glide 构建完 RequestBuilder 后,会通过 into() 方法把最后的结果渲染到对应 ImageView (当然我们也可以不渲染到 ImageView 中,这需要我们自定义)。所以我们也以 RequestBuilder#into() 方法作为今天分析的入口函数:
Java
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
// 校验必须在主线程
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
// 如果没有设置图片的裁剪方式,根据 ImageView 的 ScaleType 来计算。
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
// 计算裁剪方式
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
// 将 ImageView 封装成 Target
glideContext.buildImageViewTarget(view, transcodeClass),
/* targetListener= */ null,
requestOptions,
// 回调线程设置成主线程
Executors.mainThreadExecutor());
}
简单说明下上面的代码:
into()方法必须在主线程调用。- 如果
RequestBuilder没有设置裁剪方式,需要通过ImageView#getScaleType()来计算,处理裁剪方式的类是Transformations,它被保存在options中,后面我们会再看到它的出现。 - 然后通过
GlideContext#buildImageViewTarget()将ImageView封装成ViewTarget对象,这里要注意我们的trascodeClass是Drawable,它表示ViewTarget最后能够处理渲染的对象格式,然后继续调用into()方法。
我们去看看 GlideContext#buildImageViewTarget() 方法是如何构建 ViewTarget 的:
Java
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
继续调用 ImageViewTargetFactory#buildTarget() 方法:
Java
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(
@NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
它所支持的 transcodeClass 只能是 Bitmap 或者 Drawable,我们的 demo 中是 Drawable,最终的 ViewTarget 实现类是 DrawableImageViewTarget()。
在看完了 ViewTarget 创建后,我们继续我们的主流程,继续看 into() 方法:
Java
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
// 如果没有这是 model,直接报错。
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
// 构建 Request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
// 获取上次的 Request
Request previous = target.getRequest();
// 如果上次的 Request 和 当前的请求一致,直接开始上次的请求
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
// 清除 Target 中上次的请求。
requestManager.clear(target);
// 将当前的 Request 设置到 Target 中。
target.setRequest(request);
// 将 target 和 request 通知 RequestManager
requestManager.track(target, request);
return target;
}
简单说明下上面的代码:
- 检查是否有设置
model,如果没有就直接报错,我们设置的请求url就是model。 - 通过
buildRequest()构建Request(后面重点分析这个方法)。 - 判断
ViewTarget中上次的Request和当前的Request是否一致,如果一致,就直接返回当前方法(返回之前会判断一下上次的Request的运行状态,如果没有运行调用对应的begin()方法)。 - 通过
RequestManager#clear()方法清除Target中的Request。 - 通过
Target#setRequest()方法将当前Request添加到Target中。 - 将
Target和Request通知RequestManager。
我们简单看看 ViewTarget#setRequest() 方法是如何设置 Request 的:
Java
@Override
public void setRequest(@Nullable Request request) {
setTag(request);
}
private void setTag(@Nullable Object tag) {
isTagUsedAtLeastOnce = true;
view.setTag(tagId, tag);
}
Request 其实就是被添加到 View 的 tag 上,对应的 tagId 是 R.id.glide_custom_view_target_tag。
我们再看看 RequestManager#track() 方法是如何处理 Target 和 Request 的:
Java
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
这里 target 交由 TargetTracker 处理;request 交由 RequestTracker 来处理。
Java
public void track(@NonNull Target<?> target) {
targets.add(target);
}
TargetTracker 处理非常简单,直接添加到列表中。
再看看 RequestTracker#runRequest() 方法:
Java
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
将 request 添加到 requests 列表中,如果当前没有暂停(也就是 onStart() 生命周期)调用 Request#begin() 方法;如果当前已经被暂停,会调用 Request#clear() 方法,然后添加到 pendingRequests 列表中。
我们继续看看 RequestBuilder#into() 方法中调用过的 buildeRequest() 方法(希望你还没有忘记),看看它是如何构建 Request 的。
Java
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/* requestLock= */ new Object(),
target,
targetListener,
/* parentCoordinator= */ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
继续看 buildRequestRecursive() 方法的实现:
Java
private Request buildRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
// 如果有 ErrorBuilder,构建一个 ErrorRequestCoordinator,同时它作为 parentCoordinator
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
// 构建 MainRequest
Request mainRequest =
buildThumbnailRequestRecursive(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
// 如果没有对 Error 的处理,直接返回 mainRequest
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
// 通过 errorBuilder 构建 errorRequest。
Request errorRequest =
errorBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
// 将 mainRequest 和 errorRequest 添加到 ErrorRequestCoordinator 中
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
简单说明下上面的方法:
- 如果有
errorBuilder,构建一个ErrorRequestCoordinator,同时它也是后续请求的parent。 - 通过
buildThumbnailRequestRecursive()构建mainRequest。如果没有errorBuilder,直接把mainRequest作为结果返回方法。 - 通过
errorBuilder构建errorRequest。 - 将
mainRequest和errorRequest添加到ErrorRequestCoordinator中,然后把它作为结果返回。
我们继续看看 buildThumbnailRequestRecursive() 方法是如何 mainRequest 的。
Java
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// 判断是否有 thumbnailBuilder
if (thumbnailBuilder != null) {
if (isThumbnailBuilt) {
throw new IllegalStateException(
"You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority =
thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority()
: getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
// 创建一个 ThumbnailRequestCoordinator 对象
ThumbnailRequestCoordinator coordinator =
new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
// 构建 fullRequest,这其实就是我们的主请求
Request fullRequest =
obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// 构建 thumbRequest。
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
requestLock,
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder,
callbackExecutor);
isThumbnailBuilt = false;
// 将 fullRequest 和 thumbRequest 添加到 ThumbnailRequestCoordinator 中
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// ...
return coordinator;
} else {
// 没有 thumbnailBuilder,直接构建一个 SingleRequest
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
上面的代码看似很多,其实非常简单:
- 判断是否有
thumbnailBuilder(也就是缩略图),如果没有,直接构建一个SingleRequest返回,真实的请求实现都是SingleRequest兑现。 - 构建一个
ThumbnailRequestCoordinator对象,它会作为后续请求的parent。 - 构建主请求
fullRequest和缩略图请求thumbRequest,并把他们添加到ThumbnailRequestCoordinator中,然后将它作为结果返回。
所以到这里我们可以做一个请求构建的总结了,我们以最复杂的情况为例子来说明,也就是同时有 ErrorRequest 和 ThumbnailReqeust 的请求:
首先构建一个 ErrorRequestCoordinator,然后通过 errorRequestBuilder 构建一个 errorRequest,继续构建一个 thumbnailRequest。他们都会被添加到 ErrorRequestCoordinator 中,他们的 parent 也都是 ErrorRequestCoordinator。
构建 thumnailRequest 时,先创建一个 ThumbnailRequestCoordinator,然后构建一个 fullRequest,也就是主请求,然后构建一个 thumbnailRequest,也就是缩略图请求。他们也都被添加到 ThumbnailRequestCoordinator 中,parent 也都是它。
ErrorRequestCoordinator
我们先简单看看 ErrorRequestCoordinator#begin() 方法的实现:
Java
@Override
public void begin() {
synchronized (requestLock) {
if (primaryState != RequestState.RUNNING) {
primaryState = RequestState.RUNNING;
primary.begin();
}
}
}
直接触发主请求的 Request#begin()。
我们继续看看 ErrorRequestCoordinator#onRequestFailed() 方法中是如何处理失败请求的:
Java
@Override
public void onRequestFailed(Request request) {
synchronized (requestLock) {
// 如果当前失败的请求不是 errorRequest,也就是表示主请求失败了
if (!request.equals(error)) {
// 触发 error#begin() 方法
primaryState = RequestState.FAILED;
if (errorState != RequestState.RUNNING) {
errorState = RequestState.RUNNING;
error.begin();
}
return;
}
// 以下的情况表示主请求和失败请求都失败了
errorState = RequestState.FAILED;
if (parent != null) {
// 通知 parent 请求失败了
parent.onRequestFailed(this);
}
}
}
如果主请求失败,就会触发 error 请求开始;如果主请求和错误的请求都失败,就表示当前请求失败了,然后它会通知 parent。
ThumbnailRequestCoordinator
Java
@Override
public void begin() {
synchronized (requestLock) {
isRunningDuringBegin = true;
try {
// 如果 full 请求没有完成,同时 thumb 也没有在请求中,触发 thumb 请求。
if (fullState != RequestState.SUCCESS && thumbState != RequestState.RUNNING) {
thumbState = RequestState.RUNNING;
thumb.begin();
}
// 如果 full 没有在请求中,触发 full 的请求。
if (isRunningDuringBegin && fullState != RequestState.RUNNING) {
fullState = RequestState.RUNNING;
full.begin();
}
} finally {
isRunningDuringBegin = false;
}
}
}
如果 full 请求没有完成,同时 thumb 也没有在请求中,触发 thumb 请求;如果 full 没有在请求中,触发 full 的请求。也就是它会同时触发 full 和 thumb 的请求。
我们继续看看 onRequestSuccess() 方法是如何处理请求成功的任务的:
Java
@Override
public void onRequestSuccess(Request request) {
synchronized (requestLock) {
if (request.equals(thumb)) {
thumbState = RequestState.SUCCESS;
return;
}
fullState = RequestState.SUCCESS;
if (parent != null) {
parent.onRequestSuccess(this);
}
if (!thumbState.isComplete()) {
thumb.clear();
}
}
}
如果是 thumb 请求成功,只是简单更新状态,然后返回;如果是 full 请求成功,会通知 parent,然后把 thumb 的请求取消掉。
我们再看看它是如何处理请求失败的任务的:
Java
@Override
public void onRequestFailed(Request request) {
synchronized (requestLock) {
if (!request.equals(full)) {
thumbState = RequestState.FAILED;
return;
}
fullState = RequestState.FAILED;
if (parent != null) {
parent.onRequestFailed(this);
}
}
}
也是朴实无华的代码,当 thumb 请求失败了,也是简单更新状态;full 请求失败了,更新 状态,同时通知 parent。
简单介绍 Registry
Registry 中注册了许多的重要的功能组件,它是通过 RegistryFactory 来创建实例和初始化的:
Java
@Synthetic
static Registry createAndInitRegistry(
Glide glide,
List<GlideModule> manifestModules,
@Nullable AppGlideModule annotationGeneratedModule) {
BitmapPool bitmapPool = glide.getBitmapPool();
ArrayPool arrayPool = glide.getArrayPool();
Context context = glide.getGlideContext().getApplicationContext();
GlideExperiments experiments = glide.getGlideContext().getExperiments();
Registry registry = new Registry();
// 注册默认的系统组件
initializeDefaults(context, registry, bitmapPool, arrayPool, experiments);
// 注册自定义的组件,或者替换默认的系统组件
initializeModules(context, glide, registry, manifestModules, annotationGeneratedModule);
return registry;
}
通过 initializeDefaults() 来注册系统组件,等我们后续需要时再来查看这个方法;通过 initializeModules() 来添加默认的组件,我们先来看看它的实现:
Java
private static void initializeModules(
Context context,
Glide glide,
Registry registry,
List<GlideModule> manifestModules,
@Nullable AppGlideModule annotationGeneratedModule) {
for (GlideModule module : manifestModules) {
try {
module.registerComponents(context, glide, registry);
} catch (AbstractMethodError e) {
throw new IllegalStateException(
"Attempting to register a Glide v3 module. If you see this, you or one of your"
+ " dependencies may be including Glide v3 even though you're using Glide v4."
+ " You'll need to find and remove (or update) the offending dependency."
+ " The v3 module name is: "
+ module.getClass().getName(),
e);
}
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(context, glide, registry);
}
}
不知道你是否还记得我们是怎么把原来的网络请求替换成 OkHttp 的?就是要通过上面方法触发我们自定义的 AppGlideModule 的 registerComponents() 方法,通过这个方法我们就可以替换原有的网络请求为 OkHttp。
看到这里你可能还是不太清楚 Registry 中具体注册了什么样功能的组件。我这里以一次简单的网络请求任务来描述一下其中会用到哪些组件:
首先我们输入的 url 是一个 String 对象,在 Glide 内部中被称为 model (它也可以是 File 类型,Drawable 类型等等),首先就需要 ModelLoader 来转换处理 model。所以 ModelLoader 就有一个输入类型和输出类型,首先要找到一个 ModelLoader 将 String 类型的 model 转换成 Url;然后继续找到一个 ModelLoader 将 Url 类型的 model 转换成 GlideUrl;最后找到将 GlideUrl 转换成 InputStream 类型的 ModelLoader,没错这个 ModelLoader 其实也就是执行的网络请求,它也是处理的最后一个 ModelLoader,最后的处理结果就需要交由下一站的组件来处理。
这也是为什么替换原有的网络请求为 OkHttp,的代码是下面这样:
Kotlin
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
super.registerComponents(context, glide, registry)
registry.replace(
GlideUrl::class.java,
InputStream::class.java,
OkHttpUrlLoader.Factory(appOkHttpClient)
)
}
ModelLoader 处理的下一站就是 Decoder,我们的 ModelLoader 的输出类型是 InputStream,我们就需要找到一个 Decoder 支持的输入类型是 InputStream的,把 InputStream 解码成 Bitmap。
在到下一站就是 Transcoder,同样的它也是有一个输入类型和输出类型,Decoder 传过来的类型是 Bitmap,我们需要将它处理成 ViewTarget 需要的 Drawable 类型,然后 ImageView 就能够直接渲染 Drawable 了。
我只是简单介绍了 Registry 中的 ModelLoader、Decoder 和 Transcoder 组件,他们是非常核心的组件。其中还有一些别的组件,比如在缓存到文件时就需要将 Bitmap 重新编码,这时就需要 Encoder。
最后
本篇文件介绍了 Reqeust 和 RequestCoordinator,还简单介绍了 Registry 中的核心组件(但是没有看源码)。由于本篇文章的篇幅也不短了,为了不像第一篇文章那样过长,所以后续的文章继续讲 SingleRequest 中是如何执行请求的。