当 Glide 从网络加载原始的数据的时候,会来到 HttpUrlFetcher#loadData()
方法,在 Glide 4.9.0 执行流程源码解析 中说过,当加载完成后,会通过 callback.onDataReady()
方法将结果回传,最终会回溯到 DecodeJob#onDataFetcherReady
这个方法中,下面将会回溯的具体流程进行分析。
// 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#loadData()
中得到加载的数据的 InputStream
之后,会将其传入回调方法进行处理。
其中 callback
是在调用方法时传递进来的。而方法是在 SourceGenerator#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;
}
可以看到看到传递的 callback
即为 SourceGenerator
对象自身(其实现了 DataCallback
接口)。
// SourceGenerator.java
public void onDataReady(Object data) {
...
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
// 将数据赋值给 dataToCache
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything,
// we should reschedule to get back onto Glide's thread.
// 数据加载回调 onDataReady() 是在子线程中,应该切换回 Glide 的线程。
// 进一步回调,cb 是在 new SourceGenerator 时传递过来的,为 DecodeJob 对象
cb.reschedule();
} else {
...
}
}
// 注意 FetcherReadyCallback#reschedule() 的目的就是为了请求在 Glide 所属的线程
// 中再次调用 DataFetcherGenerator#startNext() 方法,
// DataFetcherGenerator 即为 SourceGenerator 的父类。
interface FetcherReadyCallback {
/**
* Requests that we call startNext() again on a Glide owned thread.
*/
void reschedule();
...
}
SourceGenerator#cb
是在初始化的时候传递过来的。更具体的,是在 DecodeJob#getNextGenerator()
方法中创建时传递进来的。
// DecodeJob.java
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
...
case SOURCE:
// 对应加载的图片的 Generator
return new SourceGenerator(decodeHelper, this);
...
}
}
public void reschedule() {
// 将 runReason 状态更新为 RunReason.SWITCH_TO_SOURCE_SERVICE
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
// callback 则是在 `DecodeJob#init()` 时从外部传递进来的对应的 EngineJob 对象
callback.reschedule(this);
}
可以看到 new SourceGenerator 时第二参数传递的是 DecodeJob 对象自身(其实现了 FetcherReadyCallback
接口)。
因此 SourceGenerator#onDataReady()
中执行 cb.reschedule()
实际上是执行 DecodeJob#reschedule()
。
然后又会进一步调用 callback.reschedule(this)
。callback
则是在 DecodeJob#init()
时从外部传递进来的,实际上为对应的 EngineJob 对象。
具体是在 Engine#load() 中,当内存缓存中没有获取到目标资源时,就会进一步从磁盘或者网络获取资源。此时就会构建 EngineJob 与 DecodeJob 对象。
因此在 DecodeJob#reschedule()
又会进一步回调 EngineJob#reschedule()
。
// EngineJob.java
public void reschedule(DecodeJob<?> job) {
getActiveSourceExecutor().execute(job);
}
getActiveSourceExecutor()
会获得对应的 GlideExecutor
,调用 GlideExecutor#execute()
实际上就是使用 GlideExecutor
内部的线程池来处理 Runnable
(DecodeJob
实现了 Runnable
接口)。
从而实现了前面(在 SourceGenerator#onDataReady()
方法中)说的从加载资源的子线程切换到 Glide 线程。
因此,此时又会执行 DecodeJob#run()
方法,进而执行 DecodeJob#runWrapped()
方法。
// DecodeJob.java
private void runWrapped() {
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);
}
}
// 非静态内部类
private enum RunReason {
/** The first time we've been submitted. */
INITIALIZE,
/**
* We want to switch from the disk cache service to the source executor.
*/
SWITCH_TO_SOURCE_SERVICE,
/**
* We retrieved some data on a thread we don't own and want to switch back to our thread to
* process the data.
*/
DECODE_DATA,
}
此时 runReason
已经变为 SWITCH_TO_SOURCE_SERVICE
了(在回调 DecodeJob#reschedule()
被赋值更新的)。
因此此时会在 GlideExecutor
对应的线程池中去执行 runGenerators()
,进而调用 currentGenerator.startNext()
。从而实现 FetcherReadyCallback#reschedule()
的目的,即切换回 Glide 线程再次调用 startNext()
。
又回到 SourceGenerator#startNext()
。
// SourceGenerator.java
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
...
}
// 将数据缓存到磁盘中
private void cacheData(Object dataToCache) {
long startTime = LogTime.getLogTime();
try {
// 这里的 encoder 实际上为 StreamEncoder(在 Glide 的构造方法中注册的,用于处理 InputStream 类型的数据的)
Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
DataCacheWriter<Object> writer =
new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
// 缓存到磁盘中
helper.getDiskCache().put(originalKey, writer);
} finally {
loadData.fetcher.cleanup();
}
// 为 sourceCacheGenerator 赋值为 DataCacheGenerator 对象
sourceCacheGenerator =
new DataCacheGenerator(Collections.singletonList(loadData.sourceKey),
helper, this);
}
在前面的 SourceGenerator#onDataReady() 被回调的时候,会将加载的数据赋值给 dataToCache
,即 dataToCache
此时不为空,因此进入到 if 语句中。
在 cacheData()
方法中,会将加载的数据缓存到磁盘中,且会为 sourceCacheGenerator 赋值新的 DataCacheGenerator 对象。
因此对于后面的 if 语句,sourceCacheGenerator 不会为空。进入到 sourceCacheGenerator.startNext() 中,即 DataCacheGenerator#startNext()
中。
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
// DataCacheGenerator.java
public boolean startNext() {
...
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
// 这里的 fetcher 为 FileFetcher,调用其 loadData() 的时候又会把自身传递过去
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
注意,在调用 FileFetcher#loadData() 的时候,会把 DataCacheGenerator 对象自身传递过去,因为其实现了 DataFetcher.DataCallback
接口。
// FileFetcher.java
public void loadData(@NonNull Priority priority,
@NonNull DataCallback<? super Data> callback) {
try {
data = opener.open(file);
} catch (FileNotFoundException e) {
callback.onLoadFailed(e);
return;
}
callback.onDataReady(data);
}
根据 File file
得到 data
,又会回调 DataCacheGenerator#onDataReady()
。
// DataCacheGenerator.java
public void onDataReady(Object data) {
cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
}
而成员变量 DataCacheGenerator#cb
则是通过 DataCacheGenerator
的构造方法传递进来的,具体是在 SourceGenerator#cacheData()
中传递的,实际上就是 SourceGenerator
对象自身。
// SourceGenerator.java
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
// This data fetcher will be loading from a File and provide the wrong data source, so override
// with the data source of the original fetcher
cb.onDataFetcherReady(sourceKey, data, fetcher, loadData.fetcher.getDataSource(), sourceKey);
}
而 SourceGenerator#cb
在前面也说过,同样是在 new 的时候传递进来的,即 DecodeJob
对象,因此最终会回调搭到 DecodeJob#onDataFetcherReady()
。
注意,到目前为止,是在前面切换到 GlideExecutor
的线程池的线程中来执行的。
到这里,就是从 HttpUrlFetcher#loadData()
最终回溯到 DecodeJob#onDataFetcherReady()
的具体流程。