Glide加載過程源碼導(dǎo)讀:
咱們從最常用的使用方式開始走起躬翁,
即 Glide.with(this).load("https://xxxx.jpg").into(imageView);
Glide.with(this) 會根據(jù)傳入的參數(shù)不同創(chuàng)建不同的 RequestManager 對象并返回
主要有以下幾種情形:
1.Fragment:則使用 Fragment.getChildFragmentManager() 向Fragment中添加一個子Fragment(只創(chuàng)建一次焦蘑,再次調(diào)用時會先查找該子Fragment是否已存在),用于監(jiān)聽該Fragment的生命周期
2.FragmentActivity/Activity:則使用 FragmentActivity.getSupportFragmentManager()或者Activity.getFragmentManager() 向 Activity 中添加一個Fragment(只創(chuàng)建一次盒发,再次調(diào)用時會先查找該子Fragment是否已存在)例嘱,用于監(jiān)聽該Activity的生命周期
3.View:會查找該view是屬于哪一個Fragment或者Activity,然后再依據(jù)1和2的情況
4.Context:會判斷是否是Activity迹辐,則執(zhí)行第二種情形蝶防;如果不是則使用 Context.getApplicationContext() 創(chuàng)建一個和Application生命周期一致的RequestManager對象甚侣,該對象只會創(chuàng)建一次保存在 RequestManagerRetriever.applicationManager變量中
5.如果在子線程調(diào)用 with方法則會直接創(chuàng)建或返回和Application生命周期一致的RequestManager對象
接下來看看 RequestManager.load() 方法中做了些什么明吩,
首先調(diào)用 RequestManager.asDrawable() 方法返回一個 RequestBuilder 對象
接著執(zhí)行 RequestBuilder.load() 該方法內(nèi)部調(diào)用了 RequestBuilder.loadGeneric() 方法,loadGeneric方法中主要記錄了加載時傳入的 model
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
// 在load中調(diào)用了 asDrawable() 方法殷费,該方法最終執(zhí)行到下面的語句印荔,
// 即:創(chuàng)建了一個 RequestBuilder 對象,而傳入的 resourceClass 為 Drawable.class
return new RequestBuilder<>(glide, this, resourceClass, context);
// 然后執(zhí)行 RequestBuilder.load(Object model) 方法详羡,該方法直接調(diào)用到下面的RequestBuilder.loadGeneric
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
if (isAutoCloneEnabled()) {
return clone().loadGeneric(model);
}
// 只是簡單記錄了 model
this.model = model;
// 并設(shè)置 isModelSet = true
isModelSet = true;
// 然后返回 this
return selfOrThrowIfLocked();
}
接下來執(zhí)行 RequestBuilder.into(ImageView view) 方法仍律,該方法內(nèi)部
首先,創(chuàng)建了一個 Request, 不考慮error实柠,thumbnail 的情況下水泉,最終會創(chuàng)建一個 SingleRequest 對象,該對象保存了請求相關(guān)的 context,model草则,transcodeClass钢拧,requestOptions,target炕横,targetListener源内,requestListeners等相關(guān)信息膜钓,error,thumbnail 的情形下也只是對多個 SingleRequest 進(jìn)行了組合以形成一個更為復(fù)雜的 Request颂斜;
然后焚鲜,執(zhí)行 RequestManager.track(target, request); 在track方法中最終調(diào)用 Request.begin()方法啟動本次請求忿磅;
// 葱她,該方法內(nèi)部又調(diào)用了下面的方法
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
// 此處 callbackExecutor 主要用于圖片加載完成后通知加載結(jié)果
// 調(diào)用 into(ImageView view)方法時傳入的是Executors.mainThreadExecutor()吨些,即在主線程顯示圖片
....
// 創(chuàng)建 Request, 不考慮error炒辉,thumbnail 的情況下黔寇,最終會創(chuàng)建一個 SingleRequest 對象缝裤,
// 該對象保存了請求相關(guān)的 context,model霎苗,transcodeClass唁盏,requestOptions,target答倡,targetListener瘪撇,requestListeners等相關(guān)信息
// error港庄,thumbnail 的情形下也只是對多個 SingleRequest 進(jìn)行了組合以形成一個更為復(fù)雜的 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方法中最終調(diào)用 Request.begin()方法啟動本次請求
requestManager.track(target, request);
return target;
}
接下來看 SingleRequest.begin() 方法酌伊,
首先缀踪,獲取 target 的寬高
然后驴娃,在 SingleRequest.onSizeReady()方法中調(diào)用 engine.load() 方法
public void begin() {
synchronized (requestLock) {
....
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
// 如果寬高有效,則開始加載蔗草,所以真正的加載是在 onSizeReady 方法中
onSizeReady(overrideWidth, overrideHeight);
} else {
// 先獲取寬高信息蕉世,獲取結(jié)果會通過 onSizeReady 回調(diào)通知
target.getSize(this);
}
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE) && canNotifyStatusChanged()) {
// 開始加載回調(diào)通知
target.onLoadStarted(getPlaceholderDrawable());
}
}
}
// 在 SingleRequest.onSizeReady 中調(diào)用 Engine.load 方法開始加載
public void onSizeReady(int width, int height) {
synchronized (requestLock) {
....
// 調(diào)用 Engine.load 方法開始加載
loadStatus = engine.load(....);
....
}
}
Engine.load()方法
首先婆硬,從內(nèi)存中加載(loadFromMemory)彬犯,如果內(nèi)存中沒有谐区,再啟動異步加載
異步加載最終調(diào)用 EngineJob.start(DecodeJob decodeJob) 方法內(nèi)部會根據(jù)加載階段選擇合適的 executor 執(zhí)行 decodeJob:
加載階段主要分為:
1.從磁盤緩存的已經(jīng)過采樣和轉(zhuǎn)碼的 (downsampled/transformed) 文件加載
2.從磁盤緩存的源文件(沒做過任何修改的) 加載
3.從最原始的文件來源(網(wǎng)絡(luò)宋列、磁盤文件等)加載
public <R> LoadStatus load(.... ResourceCallback cb ....) {
// 這里的 ResourceCallback 參數(shù)傳入的是 SingleRequest 對象
....
// 根據(jù)請求的相關(guān)信息構(gòu)建緩存的 key
EngineKey key =keyFactory.buildKey(....);
EngineResource<?> memoryResource;
synchronized (this) {
// 先查詢 內(nèi)存中是否已存在本次請求的資源
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
// 如果內(nèi)存中不存在本次請求的資源,則開啟異步加載
return waitForExistingOrStartNewJob(....);
}
}
// 如果內(nèi)存中 已存在 本次請求的資源灭返,則直接通知回調(diào)接口
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE, false);
return null;
}
// Engine.waitForExistingOrStartNewJob()
private <R> LoadStatus waitForExistingOrStartNewJob(.... ResourceCallback cb ....) {
// 這里的 ResourceCallback 參數(shù)傳入的是 SingleRequest 對象
....
// 根據(jù) key 查詢是否已經(jīng)存在 EngineJob 熙含,
// 如果已存在則不用開啟新的 EngineJob 去加載相同的資源了艇纺,
// 只需要將回調(diào)接口添加到 EngineJob 以便于加載成功后通知
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
// 創(chuàng)建一個 EngineJob 對象
EngineJob<R> engineJob = engineJobFactory.build(key ....);
// 創(chuàng)建 DecodeJob 對象蚓聘,真正的異步加載(從磁盤/網(wǎng)絡(luò)等)都是在 DecodeJob 中完成的盟劫,
// DecodeJob 實現(xiàn) Runnable 捞高,所以可以在 executor 中執(zhí)行
// EngineJob 是實現(xiàn)了 DecodeJob.Callback 的,后續(xù) DecodeJob 加載流程中會用于切換 executor氢哮,或者接收加載成功/失敗的回調(diào)
DecodeJob<R> decodeJob = decodeJobFactory.build(.... key .... engineJob);
....
// 將 engineJob 加入 jobs
jobs.put(key, engineJob);
// 將回調(diào)接口添加到 EngineJob 以便于加載成功后通知
engineJob.addCallback(cb, callbackExecutor);
// EngineJob.start 方法內(nèi)部會根據(jù)加載階段選擇合適的 executor 執(zhí)行 decodeJob
// 加載階段主要分為:
// 1.從磁盤緩存的已經(jīng)過采樣和轉(zhuǎn)碼的 (downsampled/transformed) 文件加載
// 2.從磁盤緩存的源文件(沒做過任何修改的) 加載
// 3.從最原始的文件來源(網(wǎng)絡(luò)冗尤、磁盤文件等)加載
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
接下來看 DecodeJob.run 方法
DecodeJob 會根據(jù)磁盤緩存策略胀溺,嘗試不同的加載來源
默認(rèn)磁盤緩存策略下 DiskCacheStrategy.decodeCachedResource() 和 DiskCacheStrategy.decodeCachedData() 都返回 true仓坞,
也即 先嘗試從磁盤緩存的已經(jīng)過采樣和轉(zhuǎn)碼的 (downsampled/transformed) 文件加載无埃,
如果緩存中沒有,再嘗試從磁盤緩存的源文件(沒做過任何修改的) 加載侦镇,
如果緩存中依然沒有,再嘗試從最原始的文件來源(網(wǎng)絡(luò)震捣、磁盤文件等)加載蒿赢。
public void run() {
DataFetcher<?> localFetcher = currentFetcher;
try {
// 加載的邏輯在 runWrapped 方法中
runWrapped();
} catch (Throwable t) {
} finally {
// DataFetcher 是真正用來從磁盤或網(wǎng)絡(luò)加載文件的剩胁,
// 其內(nèi)部可能打開了一些 InputStream 等資源昵观,
// 所以必須調(diào)用其 cleanup 方法給其一個關(guān)閉資源的機(jī)會
if (localFetcher != null) {
localFetcher.cleanup();
}
}
}
// DecodeJob.runWrapped 方法
private void runWrapped() {
// DecodeJob創(chuàng)建時啊犬,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:
// 默認(rèn)配置中 decodeCachedResource 返回 true
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
// 默認(rèn)配置中 decodeCachedData 返回 true
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// RequestBuilder 可以配置 onlyRetrieveFromCache,其默認(rèn)值為 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 負(fù)責(zé)從磁盤緩存的已經(jīng)過采樣和變換的 (downsampled/transformed) 文件加載
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
// DataCacheGenerator 負(fù)責(zé)從磁盤緩存的源文件(沒做過任何修改的) 加載
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
// SourceGenerator 負(fù)責(zé)從最原始的文件來源(網(wǎng)絡(luò)、用戶手機(jī)中的文件等)加載
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
DecodeJob 的執(zhí)行流程比較繞峻贮,我繪制了一個執(zhí)行流程圖如下: