Glide.with(imageView.context).load(url).into(imageView)
這一串代碼是加載圖片的最簡形式.
分別傳遞了3個參數
- context主要用于生成framgnet控制glide加載生命周期
- 基于url生成key,找到緩存中對應的圖片資源
- 有了圖片資源后,加載到imageView中
生命周期的控制——RequestManager
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
getRetriever中獲取glide的RequestManagerRetriever
- 若glide為null,則會用單例模式構造
- RequestManagerRetriever
RequestManagerRetriever中通過對context類型的判斷,生成RequestManagerFragment/SupportRequestManagerFragment.通過這個framgnet獲取生命周期和RequestManagerTreeNode,生成RequestManager
- 這里的生命周期和androidX中的不是同一個,但作用類似
- 同一個context只會生成一個RequestManagerFragment/SupportRequestManagerFragment,并且只有這一個RequestManager
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
...
// If we're the application level request manager, we may be created on a background thread.
// In that case we cannot risk synchronously pausing or resuming requests, so we hack around the
// issue by delaying adding ourselves as a lifecycle listener by posting to the main thread.
// This should be entirely safe.
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
...
}
RequestManager本身繼承LifecycleListener,在構建的時候注冊監聽.
- 除了注冊自身的監聽,還有個ConnectivityMonitor,在有網絡權限時,默認實現為DefaultConnectivityMonitor.DefaultConnectivityMonitor在接受到onStart事件時,會注冊一個監聽網絡狀態的廣播,onStop時注銷.當無網狀態切換到有網的時候,廣播便會執行requestTracker.restartRequests(),開始處理請求.
RequestManager的onStart和onStop方法中,會針對requestTracker和targetTracker這兩個對象操作
/**
* Lifecycle callback that registers for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused
* requests.
*/
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
/**
* Lifecycle callback that unregisters for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
*/
@Override
public synchronized void onStop() {
pauseRequests();
targetTracker.onStop();
}
- RequestTracker 負責跟蹤Request
- TargetTracker 負責跟蹤Target
RequestTracker和TargetTracker都是對數組進行操作,既然是數組,通過查看對數組操作的函數,最后定位到RequestBuilder.into函數中
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Request request = buildRequest(target, targetListener, options, callbackExecutor);
...
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
加載請求的構建——RequestBuilder
在into方法中,構建了target與request
-
Target繼承LifecycleListener,會被TargetTracker控制;Target有很多實現,這里transcodeClass對應的是Drawable.class,生成DrawableImageViewTarget
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) { ... return into( glideContext.buildImageViewTarget(view, transcodeClass), /*targetListener=*/ null, requestOptions, Executors.mainThreadExecutor()); }
public class ImageViewTargetFactory { @NonNull @SuppressWarnings("unchecked") public <Z> ViewTarget<ImageView, Z> buildTarget( @NonNull ImageView view, @NonNull Class<Z> clazz) { if (Bitmap.class.equals(clazz)) { return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); } else if (Drawable.class.isAssignableFrom(clazz)) { return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); } else { throw new IllegalArgumentException( "Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)"); } } }
-
Request的基本實現是SingleRequest,同樣會被RequestTracker控制
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); }
上面構建Target時,之所以說transcodeClass == Drawable.class.是因為transcodeClass的類型由Glide.load函數決定的.
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
加載的邏輯
RequestManager的onStart執行時,初始status == Status.PENDING
public void begin() {
synchronized (requestLock) {
...
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
}
}
target.getSize(target為DrawableImageViewTarget,getSize為基類ViewTarget函數)→
SizeDeterminer.getSize(獲取寬高,若寬高無效,通過注冊ViewTreeObserver,在onPreDraw中獲取寬高,獲取到有效數據后,回調SingleRequest.onSizeReady)→
SingleRequest.onSizeReady→
Engine.load(這個時候會通過Glide.load等參數構建EngineKey,通過key去activeResources/cache中取數據)
- activeResources 沒有大小限制.保存活躍的圖片資源.
- cache 有大小限制.保存不展示的圖片資源
- 受生命周期控制,當RequestManagerFragment/SupportRequestManagerFragment銷毀的時候,從activeResources中remove添加到cache中
→waitForExistingOrStartNewJob
從activeResources/cache中沒取到數據時,則執行這個方法,如果任務已經存在,則不重復創建,只添加回調
-
若任務不存在,則構建EngineJob和DecodeJob,并在EngineJob中啟動DecodeJob
public synchronized void start(DecodeJob<R> decodeJob) { this.decodeJob = decodeJob; GlideExecutor executor = decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor(); executor.execute(decodeJob); }
這里利用線程池執行DecodeJob(DecodeJob本身繼承Runnable)
-
decodeJob.willDecodeFromCache() 會根據diskCacheStrategy來判斷使用那個線程池
boolean willDecodeFromCache() { Stage firstStage = getNextStage(Stage.INITIALIZE); return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE; } 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); } }
-
diskCacheStrategy對象得追溯到Glide構造的時候,有默認實現,也有set方法.共有5種類型,ALL/NONE/DATA/RESOURCE/AUTOMATIC.默認實現為AUTOMATIC.
public final class GlideBuilder { private RequestOptionsFactory defaultRequestOptionsFactory = new RequestOptionsFactory() { @NonNull @Override public RequestOptions build() { return new RequestOptions(); } }; public GlideBuilder setDefaultRequestOptions(@Nullable final RequestOptions requestOptions) { return setDefaultRequestOptions( new RequestOptionsFactory() { @NonNull @Override public RequestOptions build() { return requestOptions != null ? requestOptions : new RequestOptions(); } }); } }
-
通過上面的分析可知,當設置的DiskCacheStrategy == AUTOMATIC == RESOURCE == ALL的時候 firstStage == Stage.RESOURCE_CACHE. DiskCacheStrategy == DATA 時 firstStage == Stage.DATA_CACHE,便會啟動diskCacheExecutor.
- 線程池數量為1
-
只有DiskCacheStrategy == NONE,才會啟動getActiveSourceExecutor.useUnlimitedSourceGeneratorPool和useAnimationPool默認為false,則會啟動sourceExecutor
- 線程池數量由CPU核心數決定,最小為4個
private GlideExecutor getActiveSourceExecutor() { return useUnlimitedSourceGeneratorPool ? sourceUnlimitedExecutor : (useAnimationPool ? animationExecutor : sourceExecutor); }
public static int calculateBestThreadCount() { if (bestThreadCount == 0) { bestThreadCount = Math.min(MAXIMUM_AUTOMATIC_THREAD_COUNT, RuntimeCompat.availableProcessors()); } return bestThreadCount; }
DecodeJob執行完成后,會回調EngineJob.onResourceReady→
EngineJob.notifyCallbacksOfResult
- CallResourceReady.run()→SingleRequest.onResourceReady→target.onResourceReady→設置資源
- Engine.onEngineJobComplete(將資源存儲到activeResources中)
加載過程——DecodeJob
- ResourceCacheGenerator 從內存中獲取數據
- DataCacheGenerator 從本地緩存中獲取,并存儲到內存中
- SourceGenerator 從網絡獲取圖片,并存儲到本地
run→
runWrapped(初始化時,runReason == INITIALIZE)→
getNextStage(根據diskCacheStrategy,更新Stage)→
getNextGenerator(根據stage,獲取需要執行的generator)→
runGenerators(while循環執行generator.startNext)→
reschedule(當循環到stage =SOURCE時執行,currentGenerator = SourceGenerator 。交給線程池,重新run)→
run→
runWrapped(runReason = SWITCH_TO_SOURCE_SERVICE)→
SourceGenerator.startNext(初始邏輯,獲取loadData中的fetcher,執行fetcher的加載邏輯,fetcher執行成功后)→
SourceGenerator.onDataReady→
DecodeJob.reschedule(重新調度)→
run→
runWrapped(runReason = SWITCH_TO_SOURCE_SERVICE)→
SourceGenerator.startNext(寫入本地文件邏輯)→
SourceGenerator.cacheData→
DataCacheGenerator.startNext(找到對應的LoadData,加載數據,加載完成執行callback onDataReady,再接口回調至SourceGenerator.onDataFetcherReady,再接口回調至DecodeJob.onDataFetcherReady)→
reschedule(runReason = RunReason.DECODE_DATA,重新調度)→
run→
runWrapped(runReason = SWITCH_TO_SOURCE_SERVICE)→
decodeFromRetrievedData→
decodeFromData(根據currentData類型,currentDataSource數據源類型,在Registry中找到對應的decoder和transcoder,并組建出decodePaths;根據decodePaths組建LoadPath;根據LoadPath獲取Resource<>,正常為LazyBitmapDrawableResource類型)→
notifyEncodeAndRelease→
notifyComplete→觸發EngineJob.onResourceReady
總結
- Glide在加載時,會生成全局唯一的glide和engine.
- 每個activity加載圖片時,都會額外創建一個不可見的fragmnt,用于控制生命周期,基于此生成requestManager.
- 每個加載請求都會生成target與request,target中收集了view信息及view資源類型.在target確認好view的寬高后,會通過request觸發engine的加載邏輯.
- engine會嘗試從activeResources和cache中加載數據,未成功,便會創建engineJob和decodeJob.
- engineJob會啟動decodeJob,嘗試從ResourceCacheGenerator/DataCacheGenerator/SourceGenerator中獲取數據.
- 取得數據后,便交由target設置資源,同時保存到engine的activeResources中.
- 當activity銷毀時,觸發生命周期銷毀邏輯,資源從activeResources中remove添加到cache中.
調試日志
adb shell setprop log.tag.Engine VERBOSE 根據打印內容判斷加載源
- Started new load 磁盤或者網絡
- Loaded resource from active resources
- Loaded resource from cache
DecodeJob|Engine|OkHttpLoadImg|PrintingEventListener|SourceGenerator|loadImg
關閉日志 adb shell setprop log.tag.Engine ERROR