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
中是如何执行请求的。