從Glide圖片加載流程深入分析源碼
不知道有沒有小伙伴跟我一樣,使用Glide已經(jīng)有好多年,平時看源碼比較零碎,對Glide的源碼只能算一知半解,面試遇到分析Glide的源碼,無從說起……
那今天就從0開始,對Glide源碼進(jìn)行一個整體的梳理,更進(jìn)一步的了解Glide的原理。
注意:此文章基于Glide 4.11.0版本
眾所周知,我們使用Gilde加載圖片時,最常用的一行代碼:
Glide.with(context).load(url).into(imageView)
這里就只先分析此行代碼的主線流程,省略了其他的配置方法。
1. Glide.with()
首先從Glide的with方法開始,它是我們最開始調(diào)用的方法,有多個重載:

無論是哪個重載方法,內(nèi)部都是return了一行 getRetriever().get() 代碼:
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
先調(diào)用 getRetriever 返回了一個 RequestManagerRetriever 對象,然后在調(diào)用 RequestManagerRetriever 的 get 方法返回一個RequestManager 對象
RequestManagerRetriever的get方法,也是有多個重載:

其中最大的區(qū)別就是在于context和非context的參數(shù)的方法,實現(xiàn)各不相同:
如果是非Context的參數(shù),比如 activity、fragment、view,其中fragment和view都可以找到一個所屬的Activity對象,那么最后就會調(diào)用到get(Activity activity),并內(nèi)部調(diào)用fragmentGet方法:
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else if (activity instanceof FragmentActivity) {
return get((FragmentActivity) activity);
} else {
assertNotDestroyed(activity);
frameWaiter.registerSelf(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
在fragmentGet方法中,創(chuàng)建了一個Fragment和RequestManager:
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
// ...
}
return requestManager;
}
這里稍微提一下RequestManagerFragment,getRequestManagerFragment創(chuàng)建的RequestManagerFragment是Glide用來進(jìn)行圖片加載的生命周期管理的,最終通過FragmentManager添加到Activity上,它本身什么都不展示,只是一個空的Fragment,僅僅是通過Fragment的生命周期來管理圖片加載的請求,避免內(nèi)存泄漏問題,可以看getRequestManagerFragment方法的實現(xiàn):
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
回到主線,我們到這里就從RequestManagerRetriever中獲得了一個RequestManager對象,從而就可以開始第二步動作:load
2. Glide.with().load()
當(dāng)我們獲得一個RequestManager后,就可以接著調(diào)用.load()的方法,現(xiàn)在的調(diào)用就就到了Glide.with().load(),可以看到load也是有多個重載方法,可以支持各種數(shù)據(jù)的load,包括file、string的url,uri等等……

load內(nèi)部是通過調(diào)用asDrawable方法,asDrawable再調(diào)用了as方法,創(chuàng)建了一個RequestBuilder并返回:
asDrawable():
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
as():
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
Glide.with().load().into()
這就是我們調(diào)用load方法之后得到RequestBuilder的由來,得到RequestBuilder之后,按照邏輯順序調(diào)用RequestBuilder的into方法,也是主線邏輯里面最重要的部分:
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
// ...
// 構(gòu)建Request請求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// ...
return target;
}
requestManager.clear(target);
target.setRequest(request);
// 執(zhí)行加載請求
requestManager.track(target, request);
return target;
}
這里省略了不相關(guān)的代碼,into方法中,主要是構(gòu)建了一個Request對象,然后調(diào)用requestManager.track(target, request)開始加載圖片,繼續(xù)跟蹤到requestManager.track方法,位于RequestManager.java中:
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
可以看到request繼續(xù)傳遞到requestTracker.runRequest(request)中,可以繼續(xù)跟蹤看看:
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
// ...
}
}
在RequestTracker.java類里面,runRequest調(diào)用了request.begain()方法
由于Request是一個接口,這里的request對象在構(gòu)建的時候其實是構(gòu)建了它的實現(xiàn)類SingleRequest,位于RequestBuilder.java:
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
那么在SingleRequest的begin方法里面,判斷語句有好幾個,千萬要迷路,這里的重點是onSizeReady:
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
// ...
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
// ...
}
}
繼續(xù)跟蹤onSizeReady,里面使用engine對象調(diào)用了load方法:
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
// ...
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);
// ...
}
}
繼續(xù)分析Engine的load方法,這里加載請求就揭開了Gilde的緩存機(jī)制:
public <R> LoadStatus load(
GlideContext glideContext,
Object model,
Key signature,
int width,
int height,
Class<?> resourceClass,
Class<R> transcodeClass,
Priority priority,
DiskCacheStrategy diskCacheStrategy,
Map<Class<?>, Transformation<?>> transformations,
boolean isTransformationRequired,
boolean isScaleOnlyOrNoTransform,
Options options,
boolean isMemoryCacheable,
boolean useUnlimitedSourceExecutorPool,
boolean useAnimationPool,
boolean onlyRetrieveFromCache,
ResourceCallback cb,
Executor callbackExecutor) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
// 構(gòu)建加載資源的key
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
EngineResource<?> memoryResource;
synchronized (this) {
// 從內(nèi)存中加載
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
// 內(nèi)存中沒有就等待或者是開始新的加載
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
cb.onResourceReady(
memoryResource, DataSource.MEMORY_CACHE, /* isLoadedFromAlternateCacheKey= */ false);
return null;
}
首先Glide是 loadFromMemory 從內(nèi)存中加載資源,這里的內(nèi)存細(xì)分一下,分別是 活動資源 和 內(nèi)存緩存,Glide是優(yōu)先從活動資源中獲取資源,獲取不到再從內(nèi)存緩存中獲取,如果內(nèi)存緩存也獲取不到,loadFromMemory 就返回null:
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
// 檢查是否從內(nèi)存緩存中讀取
if (!isMemoryCacheable) {
return null;
}
// 從活動緩存中讀取
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
// 從活動緩存中讀取到了資源
return active;
}
// 從活動緩存中沒有讀取到資源
// 從內(nèi)存緩存中讀取
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
// 從內(nèi)存緩存中讀取讀取到了資源
return cached;
}
return null;
}
這里從內(nèi)存緩存中讀取到了資源之后,還把資源加入到活動緩存,這樣做的目的是為了下一次獲取數(shù)據(jù)更快(先從活動資源獲取數(shù)據(jù)):
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
現(xiàn)在回過頭來看 waitForExistingOrStartNewJob 方法,這個方法是從 loadFromMemory 沒有加載到數(shù)據(jù)時才調(diào)用,waitForExistingOrStartNewJob 里面構(gòu)建了 engineJob 和 decodeJob 的對象,engineJob 對象用來啟動了一個 decodeJob ,engineJob 很簡單,就是維護(hù)了線程池,進(jìn)行線程的調(diào)度,這里在start 里面執(zhí)行了 decodeJob:
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
executor.execute(decodeJob);
}
由此看來,既然是線程調(diào)度,decodeJob 是被執(zhí)行的部分,那DecodeJob類肯定是實現(xiàn)了 Runnable 接口,并將主要的邏輯寫到了 run 方法里面,跟蹤代碼一看,果不其然:
class DecodeJob<R>
implements DataFetcherGenerator.FetcherReadyCallback,
Runnable,
Comparable<DecodeJob<?>>,
Poolable {
// ...
}
避免干擾,我將run方法里面的注釋和不相關(guān)的邏輯給刪除掉了:
public void run() {
// ...
try {
// ...
// 主要代碼,我們繼續(xù)跟蹤這個方法
runWrapped();
} catch (CallbackException e) {
throw e;
} catch (Throwable t) {
// ...
} finally {
// ...
}
}
繼續(xù)跟蹤runWrapped方法:
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
// 首次初始化并獲取資源
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
// 從磁盤緩存獲取不到數(shù)據(jù),重新獲取
runGenerators();
break;
case DECODE_DATA:
// 獲取資源成功,解碼數(shù)據(jù)
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
這里通過我的注釋應(yīng)該很容易理解這個switch語句了,至于獲取圖片成功后的 decodeFromRetrievedData,暫時停一下稍候分析,其他的兩個case語句,不管是 INITIALIZE 初始化還是 SWITCH_TO_SOURCE_SERVICE 從磁盤緩存獲取不到數(shù)據(jù)進(jìn)行重試,都是要調(diào)用 runGenerators 來獲取數(shù)據(jù),我們繼續(xù)跟蹤看看這個方法:
private void runGenerators() {
//...
// 條件語句中的 currentGenerator.startNext() 才是重點
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// ...
}
首先看while的條件語句:
- !isCancelled :如果沒有取消請求
- currentGenerator != null : currentGenerator對象不為空
- !(isStarted = currentGenerator.startNext()) : currentGenerator.startNext()的執(zhí)行結(jié)果會賦值給 isStarted
前兩個不過多解釋,主要是第三個語句:如果isStarted的值為false,表示沒有執(zhí)行成功,就會執(zhí)行while語句體里面的內(nèi)容,while語句體里面就會獲取下一個 Stage,以及通過Stage 來獲取對應(yīng)的 Generator:
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
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:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
根據(jù)兩個方法聯(lián)合分析,getNextGenerator 執(zhí)行結(jié)果:
- 第一次返回
ResourceCacheGenerator - 第二次返回
DataCacheGenerator - 第三次的返回取決于
getNextStage方法中case DATA_CACHE返回Stage.FINISHED或Stage.SOURCE,getNextGenerator方法就返回SourceGenerator或者是 null
那其實這三個Generator:ResourceCacheGenerator、DataCacheGenerator、SourceGenerator,都是實現(xiàn)自DataFetcherGenerator接口,目的是為了從不同的Generator中加載資源,如果加載成功,就將資源返回,如果加載不成功,就繼續(xù)找下一個Generator加載
不管是從哪個Generator加載數(shù)據(jù),都是通過剛才的while語句中的startNext來執(zhí)行,不同的Generator內(nèi)部實現(xiàn)不一樣,但是都大同小異,都是加載數(shù)據(jù),加載結(jié)果是通過一個叫做FetcherReadyCallback的接口進(jìn)行回調(diào),這里隨便看一個,DataCacheGenerator的startNext:
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;
// 加載資源重點代碼
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
加載資源的重點代碼是:loadData.fetcher.loadData(helper.getPriority(), this)
loadData.fetcher 獲得的是一個DataFetcher,DataFetcher是獲取資源的接口,所以loadData具體的工作其實是交給它的實現(xiàn)類來完成,它的實現(xiàn)類有HttpUrlFetcher、LocalUriFetcher、FileFetcher、AssetPathFetcher等等,用于支持各種資源的獲取。
至于加載的細(xì)節(jié),這里舉兩個例子:
- 從http url加載
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
- 從文件加載
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super Data> callback) {
try {
data = opener.open(file);
callback.onDataReady(data);
} catch (FileNotFoundException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to open file", e);
}
callback.onLoadFailed(e);
}
}
加載成功,通過callback.onDataReady(data)進(jìn)行回調(diào),加載不成功,則通過callback.onLoadFailed(e)進(jìn)行回調(diào)。
以上就是Glide加載圖片的主要流程代碼分析,因為是省略了大部分的源碼和注釋,只保留了主線代碼,所以還是要自己去跟蹤一遍,才更能理解其中的原理,謝謝觀看!