當 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()
的具體流程。