Glide加载过程源码导读:
咱们从最常用的使用方式开始走起,
即 Glide.with(this).load("https://xxxx.jpg").into(imageView);
Glide.with(this) 会根据传入的参数不同创建不同的 RequestManager 对象并返回
主要有以下几种情形:
1.Fragment:则使用 Fragment.getChildFragmentManager() 向Fragment中添加一个子Fragment(只创建一次,再次调用时会先查找该子Fragment是否已存在),用于监听该Fragment的生命周期
2.FragmentActivity/Activity:则使用 FragmentActivity.getSupportFragmentManager()或者Activity.getFragmentManager() 向 Activity 中添加一个Fragment(只创建一次,再次调用时会先查找该子Fragment是否已存在),用于监听该Activity的生命周期
3.View:会查找该view是属于哪一个Fragment或者Activity,然后再依据1和2的情况
4.Context:会判断是否是Activity,则执行第二种情形;如果不是则使用 Context.getApplicationContext() 创建一个和Application生命周期一致的RequestManager对象,该对象只会创建一次保存在 RequestManagerRetriever.applicationManager变量中
5.如果在子线程调用 with方法则会直接创建或返回和Application生命周期一致的RequestManager对象
接下来看看 RequestManager.load() 方法中做了些什么,
首先调用 RequestManager.asDrawable() 方法返回一个 RequestBuilder 对象
接着执行 RequestBuilder.load() 该方法内部调用了 RequestBuilder.loadGeneric() 方法,loadGeneric方法中主要记录了加载时传入的 model
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
// 在load中调用了 asDrawable() 方法,该方法最终执行到下面的语句,
// 即:创建了一个 RequestBuilder 对象,而传入的 resourceClass 为 Drawable.class
return new RequestBuilder<>(glide, this, resourceClass, context);
// 然后执行 RequestBuilder.load(Object model) 方法,该方法直接调用到下面的RequestBuilder.loadGeneric
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
if (isAutoCloneEnabled()) {
return clone().loadGeneric(model);
}
// 只是简单记录了 model
this.model = model;
// 并设置 isModelSet = true
isModelSet = true;
// 然后返回 this
return selfOrThrowIfLocked();
}
接下来执行 RequestBuilder.into(ImageView view) 方法,该方法内部
首先,创建了一个 Request, 不考虑error,thumbnail 的情况下,最终会创建一个 SingleRequest 对象,该对象保存了请求相关的 context,model,transcodeClass,requestOptions,target,targetListener,requestListeners等相关信息,error,thumbnail 的情形下也只是对多个 SingleRequest 进行了组合以形成一个更为复杂的 Request;
然后,执行 RequestManager.track(target, request); 在track方法中最终调用 Request.begin()方法启动本次请求;
// ,该方法内部又调用了下面的方法
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
// 此处 callbackExecutor 主要用于图片加载完成后通知加载结果
// 调用 into(ImageView view)方法时传入的是Executors.mainThreadExecutor(),即在主线程显示图片
....
// 创建 Request, 不考虑error,thumbnail 的情况下,最终会创建一个 SingleRequest 对象,
// 该对象保存了请求相关的 context,model,transcodeClass,requestOptions,target,targetListener,requestListeners等相关信息
// error,thumbnail 的情形下也只是对多个 SingleRequest 进行了组合以形成一个更为复杂的 Request
Request request = buildRequest(target, targetListener, options, callbackExecutor);
// 获取与target绑定的上一次请求,并做一些比较,判断是否是相同的请求
Request previous = target.getRequest();
....
requestManager.clear(target);
// 将request绑定到target上,
// 如果是CustomViewTarget,则主要使用了 View.setTag(int key, final Object tag)方法
target.setRequest(request);
// 在track方法中最终调用 Request.begin()方法启动本次请求
requestManager.track(target, request);
return target;
}
接下来看 SingleRequest.begin() 方法,
首先,获取 target 的宽高
然后,在 SingleRequest.onSizeReady()方法中调用 engine.load() 方法
public void begin() {
synchronized (requestLock) {
....
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果宽高有效,则开始加载,所以真正的加载是在 onSizeReady 方法中
onSizeReady(overrideWidth, overrideHeight);
} else {
// 先获取宽高信息,获取结果会通过 onSizeReady 回调通知
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) {
// 开始加载回调通知
target.onLoadStarted(getPlaceholderDrawable());
}
}
}
// 在 SingleRequest.onSizeReady 中调用 Engine.load 方法开始加载
public void onSizeReady(int width, int height) {
synchronized (requestLock) {
....
// 调用 Engine.load 方法开始加载
loadStatus = engine.load(....);
....
}
}
Engine.load()方法
首先,从内存中加载(loadFromMemory),如果内存中没有,再启动异步加载
异步加载最终调用 EngineJob.start(DecodeJob decodeJob) 方法内部会根据加载阶段选择合适的 executor 执行 decodeJob:
加载阶段主要分为:
1.从磁盘缓存的已经过采样和转码的 (downsampled/transformed) 文件加载
2.从磁盘缓存的源文件(没做过任何修改的) 加载
3.从最原始的文件来源(网络、磁盘文件等)加载
public <R> LoadStatus load(.... ResourceCallback cb ....) {
// 这里的 ResourceCallback 参数传入的是 SingleRequest 对象
....
// 根据请求的相关信息构建缓存的 key
EngineKey key =keyFactory.buildKey(....);
EngineResource<?> memoryResource;
synchronized (this) {
// 先查询 内存中是否已存在本次请求的资源
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
// 如果内存中不存在本次请求的资源,则开启异步加载
return waitForExistingOrStartNewJob(....);
}
}
// 如果内存中 已存在 本次请求的资源,则直接通知回调接口
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE, false);
return null;
}
// Engine.waitForExistingOrStartNewJob()
private <R> LoadStatus waitForExistingOrStartNewJob(.... ResourceCallback cb ....) {
// 这里的 ResourceCallback 参数传入的是 SingleRequest 对象
....
// 根据 key 查询是否已经存在 EngineJob ,
// 如果已存在则不用开启新的 EngineJob 去加载相同的资源了,
// 只需要将回调接口添加到 EngineJob 以便于加载成功后通知
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
// 创建一个 EngineJob 对象
EngineJob<R> engineJob = engineJobFactory.build(key ....);
// 创建 DecodeJob 对象,真正的异步加载(从磁盘/网络等)都是在 DecodeJob 中完成的,
// DecodeJob 实现 Runnable ,所以可以在 executor 中执行
// EngineJob 是实现了 DecodeJob.Callback 的,后续 DecodeJob 加载流程中会用于切换 executor,或者接收加载成功/失败的回调
DecodeJob<R> decodeJob = decodeJobFactory.build(.... key .... engineJob);
....
// 将 engineJob 加入 jobs
jobs.put(key, engineJob);
// 将回调接口添加到 EngineJob 以便于加载成功后通知
engineJob.addCallback(cb, callbackExecutor);
// EngineJob.start 方法内部会根据加载阶段选择合适的 executor 执行 decodeJob
// 加载阶段主要分为:
// 1.从磁盘缓存的已经过采样和转码的 (downsampled/transformed) 文件加载
// 2.从磁盘缓存的源文件(没做过任何修改的) 加载
// 3.从最原始的文件来源(网络、磁盘文件等)加载
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
接下来看 DecodeJob.run 方法
DecodeJob 会根据磁盘缓存策略,尝试不同的加载来源
默认磁盘缓存策略下 DiskCacheStrategy.decodeCachedResource() 和 DiskCacheStrategy.decodeCachedData() 都返回 true,
也即 先尝试从磁盘缓存的已经过采样和转码的 (downsampled/transformed) 文件加载,
如果缓存中没有,再尝试从磁盘缓存的源文件(没做过任何修改的) 加载,
如果缓存中依然没有,再尝试从最原始的文件来源(网络、磁盘文件等)加载。
public void run() {
DataFetcher<?> localFetcher = currentFetcher;
try {
// 加载的逻辑在 runWrapped 方法中
runWrapped();
} catch (Throwable t) {
} finally {
// DataFetcher 是真正用来从磁盘或网络加载文件的,
// 其内部可能打开了一些 InputStream 等资源,
// 所以必须调用其 cleanup 方法给其一个关闭资源的机会
if (localFetcher != null) {
localFetcher.cleanup();
}
}
}
// DecodeJob.runWrapped 方法
private void runWrapped() {
// DecodeJob创建时,runReason 的初始值是 RunReason.INITIALIZE
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
// DecodeJob.getNextStage 方法
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
// 默认配置中 decodeCachedResource 返回 true
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
// 默认配置中 decodeCachedData 返回 true
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// RequestBuilder 可以配置 onlyRetrieveFromCache,其默认值为 false
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
// DecodeJob.getNextGenerator
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
// ResourceCacheGenerator 负责从磁盘缓存的已经过采样和变换的 (downsampled/transformed) 文件加载
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// DataCacheGenerator 负责从磁盘缓存的源文件(没做过任何修改的) 加载
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// SourceGenerator 负责从最原始的文件来源(网络、用户手机中的文件等)加载
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
DecodeJob 的执行流程比较绕,我绘制了一个执行流程图如下: