对于源码的分析,是基于 Glide 最简单的使用的流程进行的:
Glide.with(MainActivity.this).load("url of image resource").into(view);
1. with() 方法
with()
方法会传入当前 activity
、fragment
等,目的就是为了获取对应的 context
,然后根据该 context
来得到 RequestManagerRetriever
对象,再进一步得到 RequestManager
对象。并且 Glide 会根据我们传入 with()
方法的参数来确定图片加载的生命周期。
这里,对于 context
只有两种情况,Application
类型的与非 Application
类型的。
对于 Application 类型的,会得到 RequestManagerRetriever#applicationManager
(虽然实质上也是 RequestManager
对象,只不过比较特殊一点,因为 Application
对象的生命周期即应用程序的生命周期,因此 Glide 并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide 的加载也会同时终止)。而非 Applicatuion
类型的则会得到普通的 RequestManager
对象。
在内部,先得到 Glide#requestManagerRetriever
,然后通过 requestManagerRetriever#get()
方法得到 RequestManager
对象。
在 requestManagerRetriever#get()
执行的过程中,会向当前的 Activity
或者 Fragment
添加一个隐藏的 Fragment
(名为 SupportRequestManagerFragment
或者 RequestManagerFragment
),这个 Fragment
是为了监听 Activity
或者 Fragment
的生命周期,使得能够感知其销毁,从而停止图片的加载。
public RequestManager get(@NonNull Fragment fragment) {
Preconditions.checkNotNull(fragment.getActivity(),
"You cannot start a load on a fragment before it is attached or after it is destroyed");
if (Util.isOnBackgroundThread()) {
return get(fragment.getActivity().getApplicationContext());
} else {
FragmentManager fm = fragment.getChildFragmentManager();
// 调用 supportFragmentGet() 来得到 RequestManager 对象
return supportFragmentGet(fragment.getActivity(), fm, fragment, fragment.isVisible());
}
}
private RequestManager supportFragmentGet(
@NonNull Context context,
@NonNull FragmentManager fm,
@Nullable Fragment parentHint,
boolean isParentVisible) {
// 进一步调用 getSupportRequestManagerFragment() 来获取 SupportRequestManagerFragment
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
// 然后得到 SupportRequestManagerFragment 中的 RequestManager 对象(如果为 null 则构建一个并
// 设置)
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
// 在 getSupportRequestManagerFragment() 中,会根据 FragmentManager 来得到对应的
// SupportRequestManagerFragment(如果为 null 则实例化一个并添加)
private SupportRequestManagerFragment getSupportRequestManagerFragment(
@NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);
// 添加 SupportRequestManagerFragment
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
2. load(String) 方法
RequestManager#load(String)
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
其中 asDrawable()
最终会构建 RequestBuilder<Drawable>
对象,其中对于 load() 传入 String 类型参数时,RequestBuilder#resourceClass
为 Drawable.class
。resourceClass
用于指定加载资源被交付的类型。
比如 RequestBuilder<GifDrawable> asGif()
、 RequestBuilder<File> asFile()
、RequestBuilder<Bitmap> asBitmap()
等等。其中,asDrawable()
是默认的,会根据情况来确定加载的资源被交付时的类型。
然后 load(String)
会进一步调用 RequestBuilder#loadGeneric()
,这里只是将传递进来的 url 字符串设置给成员变量 model。
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
因此,load()
主要用于生成一个 RequestBuilder
,该对象在后面用于对于资源的请求。
3. into() 方法
经过 Glide.with(Context).load(String)
之后,最终会得到 RequestBuilder<Drawable>
,因此 Glide.with(Context).into(ImageView)
实际上就是调用 RequestBuilder<Drawable>#into(ImageView)
。
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
// RequestBuilder 继承自 BaseRequestOptions
BaseRequestOptions<?> requestOptions = this;
// 根据 ImageView 的 scaleType 来判断是否克隆并设置额外的 option
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;
...
default:
// Do nothing.
}
}
// 然后进一步调用冲载的 into() 方法
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
(1)其中 glideContext.buildImageViewTarget(view, transcodeClass)
会构建出一个 ViewTarget<ImageView, X>
对象。这里的 transcodeClass
就是前面在 new RequestBuilder
对象时设置的,即 Drawable.class
,且 glideContext
为 GlideContext
。
// GlideContext.java
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
// 进一步调用 ImageViewTargetFactory#buildTarget()
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
// ImageViewTargetFactory.java
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)");
}
}
最终,会得到实际为 DrawableImageViewTarget
的 ViewTarget
对象,该对象是用来最终展示图片用的。
(2)进一步调用的 into() 重载方法为:
// RequestBuilder.java
// target 为前面所说的 DrawableImageViewTarget 实例
// targetListener 为 null
// options 是从上一个方法传递过来的
// callbackExecutor 为 Executors.mainThreadExecutor()
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
// 根据传递进来的参数构建出 Request
// 在主流程中,就得到一个 SingleRequest 对象,里面
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
...
return target;
}
requestManager.clear(target);
target.setRequest(request);
// 执行 request
requestManager.track(target, request);
return target;
}
在 requestManager.track(target, request)
中会调用 requestTracker.runRequest(request)
。
// RequestTracker.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);
}
}
先判断 Glide 当前是不是处理暂停状态,如果不是暂停状态就调用 Request
的 begin()
方法来执行开启请求,否则的话就先将 Request
添加到待执行队列里面,等暂停状态解除了之后再执行。
正常情况下,Request
的具体类型会是 SingleRequest
,因此进入到 SingleRequest#begin()
。
// SingleRequest.java
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
// 如果 model 等于 null,model 也就是我们在第二步 load() 方法中传入的图片 URL 地址,
// 这个时候会调用 onException() 方法。
// 在 onException() 中会调用 setErrorPlaceholder()。
// 而在 setErrorPlaceholder() 根据实际情况来选择调用 fallback()、error()、placeholder() 这几个方法
// 时设置的图片显示到 ImageView 上
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
...
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果使用了 override() API 为图片指定了一个固定的宽高
onSizeReady(overrideWidth, overrideHeight);
} else {
// 没有指定则调用 target.getSize()
// target.getSize() 方法的内部会根据 ImageView 的
// layout_width 和 layout_height 值做一系列的计算,来算出图片应该的宽高
// 计算完之后,它也会调用 onSizeReady() 方法
target.getSize(this);
}
...
}
根据前面的流程,正常情况下都会进入到 onSizeReady()
方法:
public synchronized void onSizeReady(int width, int height) {
...
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
loadStatus =
engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
}
然后进一步调用 Engine#load()
,这一部分就是加载资源的关键了。
// Engine.java
public synchronized <R> LoadStatus load(
...) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
// 首先根据目标资源的相关参数得到对应的 key 值
EngineKey key = keyFactory.buildKey(model, signature, width, height, transform
resourceClass, transcodeClass, options);
// 然后从 ActiveResources 内存缓存中去取
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
// 如果取到了则直接回调后续方法
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
// 如果在 ActiveResources 内存缓存中没有取到,则再去基于 LruCache 的内存缓存中去取
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
// 从缓存中查找 key 对应的任务,即加载资源的任务
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
// 如果取到了则表示任务已经完成,进行相应的回调即可
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
// 否则,在内存中没有获取到缓存的资源,则构建相关任务,从磁盘或者远程加载
// 构建一个新的引擎任务
EngineJob<R> engineJob =
engineJobFactory.build(
...);
// 构建解码任务
DecodeJob<R> decodeJob =
decodeJobFactory.build(
...);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
可以看到,则 Engine#load()
中,会先从内存缓存中去获取目标资源,如果没有,才会进一步去从磁盘缓存或者远程去加载资源(当然,这部分是后面的内容)。
上面说到会构建 EngineJob
和 DecodeJob
。
其中,EngineJob
对象的主要作用就是用来开启线程的,为后面的异步加载图片做准备。
而 DecodeJob
对象实现了 Runnable
接口,然后会调用 engineJob.start(decodeJob)
来启动 decodeJob
。
// EngineJob.java
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
// 得到对应的 GlideExecutor,用于提交并执行 decodeJob
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
GlideExecutor
有好几种类型的,diskCacheExecutor、sourceExecutor、sourceUnlimitedExecutor、animationExecutor
,不同类型的 GlideExecutor
用于从不同的地方 load/decode/transform data,这里的地方指的磁盘缓存、Glide 自己的缓存区等。
不同的 GlideExecutor
对象内部会持有不同的线程池,执行 GlideExecutor#execute()
,会间接调用线程池的 execute()
方法。
因此这里可以理解为将 decodeJob
提交到对应的线程池去处理。因为 decodeJob
为 Runnable
,当其被处理的时候,实际上会调用其 run()
方法。
// DecodeJob.java
public void run() {
...
// Methods in the try statement can invalidate currentFetcher, so set a local variable here to
// ensure that the fetcher is cleaned up either way.
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
}
...
}
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
// 1、得到 stage
stage = getNextStage(Stage.INITIALIZE);
// 2、根据 stage 得到对应的 Generator
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
// decodeCachedResource() 为 true 表示尝试 decode 缓存的被转换的图片
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
// decodeCachedData() 为 true 表示尝试 decode 缓存的原始图片
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
// 如果用户选择只用缓存中检索资源,则跳过从源头加载
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
// 对应被转换的图片的缓存的 Generator
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// 对应原始图片的缓存的 Generator
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// 对应加载的图片的 Generator(此时)
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
// currentGenerator 执行加载逻辑
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
在 run()
方法中,会进一步调用 runWrapped()
,此时会走 case INITIALIZE
的语句。
此时会根据不同的场景的获取不同的 Generator
来获取资源。这里主要针对 SourceGenerator
进行分析,其表示从数据源头请求数据(如通过网路从远程加载)。
(对于 ResourceCache
与 DataCache
,是针对磁盘缓存来说的,因为当资源图片从网络加载后之后,可能会经过一些列的转换,而被转换后的图片资源则对应为 Resource,而没有经过转换的原始图片,则对应为 Source。相关内容在讲关于缓存的章节有说:Glide 4.9.0 的缓存机制)
后续的逻辑,主要是在 runGenerators()
中调用 currentGenerator.startNext()
来执行加载逻辑。
// SourceGenerator.java
public boolean startNext() {
...
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
// 1. 从 DecodeHelper 的数据加载集合中, 获取一个数据加载器
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
// 2. 使用加载器中 fetcher 执行数据加载
// 网络的 url 资源对应的就是 HttpGlideUrlLoader,它对应的 ModelLoader.LoadData 中的
// fetcher 为 HttpUrlFetcher 类型
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
对于从网络加载资源,是由 HttpUrlFetcher#loadData()
来处理的。
// HttpUrlFetcher.java
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
// 获取网络图片, 内部使用了 HttpURLConnection 实现, 仅仅做了重定向的处理
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
// 回调 callback.onDataReady() 方法将结果回传
// callback 是在调用方法时传递过来的,这里即 SourceGenerator#startNext() 方法中传递的,即 SourceGenerator 对象自身
callback.onDataReady(result);
} catch (IOException e) {
callback.onLoadFailed(e);
} finally {
...
}
}
数据加载的过程也是很简单的, HttpUrlFetcher
它使用了 HttpURLConnection
发起了网络请求, 获取了数据流, 至此数据资源的获取就已经完成了, 后面要做的便是最重要的数据处理了, 它通过回调的方式将 InputStream 类型的结果一步一步的进行回调, 最终会回溯到 DecodeJob#onDataFetcherReady
这个方法中。
具体的回调流程,参见:Glide 4.9.0 关于数据加载之后的回调过程
然后,后续的对于原始数据资源的处理,参见:Glide 4.9 源码分析(一) —— 一次完整加载流程 —— 第五点 。(由于时间与篇幅原因,暂时不单独进行后续分析)
相关内容索引:
(1)Glide 4.9.0 的缓存机制
(2)Glide 4.9.0 关于数据加载之后的回调过程
(3)Glide 4.9.0 关于监听生命周期
主要参考文章:
1、Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流程(郭神的博客,基于 3.7.0 分析的)
2、Glide 源码分析解读-基于最新版Glide 4.9.0
3、Glide 4.9 源码分析(一) —— 一次完整加载流程