文章目錄
本文將分析圖片處理框架Glide的加載流程,同時也會對緩存,網絡請求,自定義模塊做相應分析,文中代碼使用的是目前(2020.3)最新的版本4.11.0。
Glide框架總覽
Glide是一個非常複雜的框架,下面我們根據各模塊的作用做出如下劃分:
圖片加載源碼分析
Glide最基本的使用流程就是下面這行代碼,其它所有擴展的額外功能都是以其建造者鏈式調用的基礎上增加的。
GlideApp.with(context).load(url).into(imageView);
下面我們將對該用法進行深入的源碼分析。
Glide.with()
Glide爲我們提供多個Glide.with()
實現,我們主要圍繞with(Context context)
展開分析
1. Glide.with(Context)
return getRetriever(activity).get(activity)
@Glide.java
RequestManagerRetriever getRetriever(context) {
...
return Glide.get(context).getRequestManagerRetriever();
}
//使用雙檢鎖方式實現單例
public static Glide get(@NonNull Context context) {
if (glide == null) {
//獲取用戶自定義GlideModule
GeneratedAppGlideModule annotationGeneratedModule =getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
void checkAndInitializeGlide(context, generatedAppGlideModule) {
...
initializeGlide(context, new GlideBuilder(), generatedAppGlideModule);
...
}
void initializeGlide(context, builder, annotationGeneratedModule) {
...
//1.1 獲取manifest中GlideModule模塊
if (annotationGeneratedModule == null || annotationGeneratedModule.isManifestParsingEnabled()) {
manifestModules = new ManifestParser(applicationContext).parse();
}
...
//將自定義GlideModule信息(factory)添加到GlideBuilder中
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory : null;
builder.setRequestManagerFactory(factory);
//1.2將GlideBuilder通過applyOptions添加到GlideModule中
for (com.bumptech.glide.module.GlideModule module : manifestModules) {
module.applyOptions(applicationContext, builder);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.applyOptions(applicationContext, builder);
}
//--> 2.創建Glide實例
Glide glide = builder.build(applicationContext);
...
//1.3 registerComponents:用於註冊編解碼器,ModelLoader等,具體可以參考@Resistry中的方法
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
Glide.glide = glide;
}
這裏使用雙檢鎖模式來獲取Glide對象的單例,在1.1中,如果沒有帶註解的GlideModule,或者該GlideModule中isManifestParsingEnabled()爲true,則調用ManifestParser解析AndroidManifest.xml中以獲取值爲“GlideModule”的meta-data配置,並將相應的自定義模塊實例化。由於可以實例化多個GlideModule,因此得到的是一個GlideModule的List集合。
在1.2中,將builder通過applyOptions方法加入到module中,在自定義module中我們通過重寫applyOptions方法可以對module進行定製。
在1.3中,提供registerComponents來修改glide中組件,用於註冊編解碼器,ModelLoader等,比如替換網絡請求成OkHttp的方法, 就是通過該函數註冊
2. GlideBuilder.build
GlideBuilder
是用來創建 Glide 實例的類,具體實現如下:
@NonNull
Glide build(@NonNull Context context) {
if (sourceExecutor == null) { //創建圖片線程池
sourceExecutor = GlideExecutor.newSourceExecutor();
}
if (diskCacheExecutor == null) { //創建硬盤緩存線程池
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
if (animationExecutor == null) { //創建動畫線程池
animationExecutor = GlideExecutor.newAnimationExecutor();
}
//TODO:默認4M,如果是低內存設備爲2M,後文[緩存機制]會有詳細分析
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
bitmapPool = new BitmapPoolAdapter();
}
}
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
if (memoryCache == null) { // 創建內存緩存
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
// 創建任務和資源管理引擎(線程池,內存緩存和硬盤緩存對象)
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
//創建requestManagerRetriever,用於創建requestManager
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled,
isImageDecoderEnabledForBitmaps);
}
這個方法中會創建BitmapPool、MemoryCache、DiskCache等對象的實例,並在最後一句創建一個Glide對象的實例,然後將前面創建的這些實例傳入到Glide對象當中,以供後續的圖片加載操作使用。
同時,我們注意到,build
中創建任何對象都有一個判空的檢查,只有對象爲空纔會去創建其實例,也就是說,我們可以applyOptions方法對這些配置對象提前初始化,進而實現更改Glide配置的功能。
具體如何自定義模塊,可以參考郭神的文章:《Android圖片加載框架最全解析(六),探究Glide的自定義模塊功能》,文中涉及如何替換網絡組件,如何替換緩存模塊等非常棒的操作。
3. Glide構造方法
將任務管理對象(registry
)、array緩存、管理引擎等傳入glideContext
中
Glide(...) {
...
//登記任務管理對象,根據任務類型,分發給相應任務進行處理
registry = new Registry();
...
//註冊編解碼器,ModelLoader等組件
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.append(InputStream.class, new StreamEncoder(arrayPool))
...
//Target工廠: 根據子類生產對應類型taget,
//包括BitmapImageViewTarget和DrawableImageViewTarget
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
engine,
isLoggingRequestOriginsEnabled,
logLevel);
}
4. RequestManagerRetriever.get
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
//如果非ApplicationContext, 將請求的生命週期同對於的Fragment/Activity綁定
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
//如果是ApplicationContext或者子線程,和Application生命週期綁定
return getApplicationManager(context);
}
@NonNull
private RequestManager supportFragmentGet(...) {
//創建一個不可見的Fragment,用於檢測Activity生命週期
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) { //確保一個Activity對於一個requestManager
Glide glide = Glide.get(context);
//創建requestManger,將Glide和Activity生命週期綁定
//參考[5.requestManager生命週期]
requestManager =
factory.build(
glide, current.getGlideLifecycle(),
current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
通過RequestManagerRetriever.get
創建RequestManager
,詳細邏輯如下:
- 如果 with 方法的
參數
爲 Activity 或者Fragment
,則最終調用RequestManagerRetriever
中的fragmentGet(Context, android.app.FragmentManager)
方法創建RequestManager
; - 如果
with
方法的參數爲android.support.v4.app.Fragment
或者android.support.v4.app.FragmentActivity
,則最終調用supportFragmentGet(Context, android.support.v4.app.FragmentManager)
方法創建RequestManager
; - 如果
with
方法的參數爲Context
,則會判斷其來源是否屬於FragmentActivity
及Activity
,則按照上面的邏輯進行處理,否則最終調用getApplicationManager(Context)
方法創建RequestManager
; - 如果在子線程或者系統版本小於17,則調用
getApplicationManager(Context)
方法創建RequestManager
。
同時,由supportFragmentGet
可知,一個Activity對應一個RequestManager。
5. RequestManager生命週期
通過RequestManagerRetriever.get
創建requestManager
,通過requestManager
將Activity
和Glide
生命週期綁定。
//RequestManager構造函數
RequestManager(...) {
//在主線程綁定Glide和Activity的生命週期
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
defaultRequestListeners =
new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
glide.registerRequestManager(this);
}
private final Runnable addSelfToLifecycle =
new Runnable() {
@Override
public void run() {
//切換到主線程
lifecycle.addListener(RequestManager.this);
}
};
//RequestManager中LifecycleLister實現
public class RequestManager
implements ComponentCallbacks2, LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
...
//開始暫停的請求
public void onStart() {
resumeRequests();
}
//停止所有的請求
@Override
public void onStop() {
pauseRequests();
}
//關閉所以的請求
@Override
public void onDestroy() {
requestTracker.clearRequests();
}
...
}
通過上面 RequestManagerRetriever
和 ResquestManager
的介紹,我們知道創建 RequestManager
時需要一個 FragmentManager
參數(全局 RequestManager
除外),那麼再創建 RequestManager
時會先創建一個不可見的 RequestManagerFragment ,通過 FragmentMamager加入到當前頁面,用這個不可見的 Fragment 即可檢測頁面的生命週期,進而將Glide
和頁面生命週期綁定。
6. Registry
Registry(com.bumptech.glide.Registry)是用來註冊管理任務執行對象的管理類,可以簡單理解爲:Registry是一個工廠,而其中所有註冊的對象都是一個工廠員工,當任務分發時,根據當前任務的性質,分發給相應員工進行處理。該類可細分爲:ModelLoaderRegistry
、EncoderRegistry
、ResourceDecoderRegistry
、ResourceEncoderRegistry
、DataRewinderRegistry
、TranscoderRegistry
和ImageHeaderParserRegistry
共七種。Registry通過各個細分的管理類通過HashMap或者List來管理執行類及其執行方法的對應關係。
public class Registry {
@NonNull
@SuppressWarnings("unchecked")
public <X> Encoder<X> getSourceEncoder(@NonNull X data) throws NoSourceEncoderAvailableException {
//根據data通過encoderRegistry來獲取對於的encoder
Encoder<X> encoder = encoderRegistry.getEncoder((Class<X>) data.getClass());
if (encoder != null) {
return encoder;
}
throw new NoSourceEncoderAvailableException(data.getClass());
}
@NonNull
public <Data> Registry append(@NonNull Class<Data> dataClass, @NonNull Encoder<Data> encoder) {
//保存dataClass和encoder對應關係到encoderRegistry工廠
encoderRegistry.append(dataClass, encoder);
return this;
}
}
public class EncoderRegistry {
private final List<Entry<?>> encoders = new ArrayList<>();
@Nullable
public synchronized <T> Encoder<T> getEncoder(@NonNull Class<T> dataClass) {
for (Entry<?> entry : encoders) {
if (entry.handles(dataClass)) {
return (Encoder<T>) entry.encoder;
}
}
return null;
}
}
7. Glide.with小結
根據上面分析,彙總成下面流程圖:
從圖上可以看到,Glide.with主要完成:
- 各類初始化,主要包括:線程池、緩存、
Engine
、requestManager
、register
和glideContext
; - 創建透明Fragment, 將Glide和視圖生命週期進行綁定。
load(url)
1.RequestManager.load
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
2.asDrawable()
@RequestManager.java
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
//最終返回了一個RequestBuilder
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
protected RequestBuilder(...) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
//初始化請求回調
initRequestListeners(requestManager.getDefaultRequestListeners());
apply(requestManager.getDefaultRequestOptions());
}
3.load(string)
@RequestBuilder.java
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
//將url賦值給RequestBuilder.model
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
可以看到,load主要是創建RequestBuilder並設置請求的URL(model),並記錄了URL已設置的狀態。
到此,我們可以總結出 RequestManager 兩個主要作用:
- 創建 RequestBuilder,用於保存請求URL和初始化請求回調;
- 通過綁定頁面生命週期來管理請求的啓動結束等
into(target)
1.RequestBuilder.into
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
//ImageView默認ScaleType爲FIT_CENTER,Glide可以通過dontTransform()或者transform(...)來關閉或使用圖片變化
if (!this.isTransformationSet() && this.isTransformationAllowed() && view.getScaleType() != null) {
switch(view.getScaleType()) {
case CENTER_CROP:
requestOptions = this.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = this.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = this.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = this.clone().optionalCenterInside();
case CENTER:
case MATRIX:
}
}
//根據transcodeClass生成對應的ViewTarget,並指定RequestBuilder.into回調主線程執行
return (ViewTarget)this.into(this.glideContext.buildImageViewTarget(view, this.transcodeClass), (RequestListener)null, (BaseRequestOptions)requestOptions, Executors.mainThreadExecutor());
}
2.GlideContext.buildImageViewTarget
return this.imageViewTargetFactory.buildTarget(imageView, transcodeClass);
3. ImageViewTargetFactory.buidTarget
@NonNull
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException("Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
根據這段代碼可知,glideContext.buildImageViewTarget
通過傳入class
類型不同,分別生成不同的ImageVieTarget
,傳入Bitmap
則生成BitmapImageViewTarget
, 傳入Drawable
則生成DrawableImageViewTarget
。
4. RequestBuilder.into
private <Y extends Target<TranscodeType>> Y into(@NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!this.isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
} else {
// -->1. 建立請求
Request request = this.buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous) && !this.isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!((Request)Preconditions.checkNotNull(previous)).isRunning()) {
previous.begin();
}
return target;
} else {
this.requestManager.clear(target);
target.setRequest(request);
// -->2. 請求追蹤
this.requestManager.track(target, request);
return target;
}
}
}
RequestBuilder.into
的實現主要是buildRequest
建立請求和requestManager.track
請求追蹤,下面我們將重點分析這兩部分。
buildRequest
// 1. 建立請求
private Request buildRequest(Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) {
// -->1.1 通過遞歸調用創建請求
return this.buildRequestRecursive(new Object(), target, targetListener, (RequestCoordinator)null, this.transitionOptions, requestOptions.getPriority(), requestOptions.getOverrideWidth(), requestOptions.getOverrideHeight(), requestOptions, callbackExecutor);
}
// 1.1 通過遞歸調用創建請求
private Request buildRequestRecursive(Object requestLock, Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) {
// 判斷當前request是否需要帶error
ErrorRequestCoordinator errorRequestCoordinator = null;
if (this.errorBuilder != null) {
//errorBuilder不爲空,此處爲[標記1]遞歸調用
errorRequestCoordinator = new ErrorRequestCoordinator(requestLock, (RequestCoordinator)parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
// --> 1.2 創建帶縮略圖的請求
Request mainRequest = this.buildThumbnailRequestRecursive(requestLock, target, targetListener, (RequestCoordinator)parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, requestOptions, callbackExecutor);
if (errorRequestCoordinator == null) {
//不帶error直接返回mainRequest
return mainRequest;
} else {
int errorOverrideWidth = this.errorBuilder.getOverrideWidth();
int errorOverrideHeight = this.errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !this.errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
// [標記1] 回調當前方法,構建帶error的請求
Request errorRequest = this.errorBuilder.buildRequestRecursive(requestLock, target, targetListener, errorRequestCoordinator, this.errorBuilder.transitionOptions, this.errorBuilder.getPriority(), errorOverrideWidth, errorOverrideHeight, this.errorBuilder, callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
}
// 1.2 創建帶縮略圖的請求
private Request buildThumbnailRequestRecursive(Object requestLock, Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, @Nullable RequestCoordinator parentCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) {
if (this.thumbnailBuilder != null) { //thumbnailBuilder不不爲空
if (this.isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a thumbnail, consider using clone() on the request(s) passed to thumbnail()");
} else {
// 獲取縮略圖配置
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions = this.thumbnailBuilder.transitionOptions;
if (this.thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority = this.thumbnailBuilder.isPrioritySet() ? this.thumbnailBuilder.getPriority() : this.getThumbnailPriority(priority);
int thumbOverrideWidth = this.thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = this.thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight) && !this.thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
// 創建ThumbnailRequestCoordinator對象
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
// 創建原圖片請求對象
Request fullRequest = this.obtainRequest(requestLock, target, targetListener, requestOptions, coordinator, transitionOptions, priority, overrideWidth, overrideHeight, callbackExecutor);
this.isThumbnailBuilt = true;
// 用遞歸方式創建縮略圖請求
Request thumbRequest = this.thumbnailBuilder.buildRequestRecursive(requestLock, target, targetListener, coordinator, thumbTransitionOptions, thumbPriority, thumbOverrideWidth, thumbOverrideHeight, this.thumbnailBuilder, callbackExecutor);
this.isThumbnailBuilt = false;
// 將原圖片請求和縮略圖請求打包到ThumbnailRequestCoordinator中
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
}
} else if (this.thumbSizeMultiplier != null) { /縮略圖縮放比例不爲空
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(requestLock, parentCoordinator);
Request fullRequest = this.obtainRequest(requestLock, target, targetListener, requestOptions, coordinator, transitionOptions, priority, overrideWidth, overrideHeight, callbackExecutor);
BaseRequestOptions<?> thumbnailOptions = requestOptions.clone().sizeMultiplier(this.thumbSizeMultiplier);
Request thumbnailRequest = this.obtainRequest(requestLock, target, targetListener, thumbnailOptions, coordinator, transitionOptions, this.getThumbnailPriority(priority), overrideWidth, overrideHeight, callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else { //沒有縮略圖,直接返回原圖片請求,通過obtainRequest最終返回一個SingleRequest對象
return this.obtainRequest(requestLock, target, targetListener, requestOptions, parentCoordinator, transitionOptions, priority, overrideWidth, overrideHeight, callbackExecutor);
}
}
代碼中fullRequest
表示原始的請求,thumbRequest
表示縮略圖請求,mainRequest表示打包了fullRequest和thumbRequest
得請求,errorRequest
錯誤重試請求;具體流程參考下面流程圖,可以方便理解:
上面我們提到,最終得到得是一個SingleRequest
得對象,SingleRequest
以來關係如下:
public final class SingleRequest<R> implements Request, SizeReadyCallback, ResourceCallback
public interface Request {
void begin();
.......
}
public interface SizeReadyCallback {
void onSizeReady(int var1, int var2);
}
public interface ResourceCallback {
void onResourceReady(Resource<?> var1, DataSource var2);
......
}
onSizeReady()和begin()是SingleRequest
最重要得兩個實現方法,相關方法得調用在requestTracker種,下面我們將分析RequstBuilder得第二個重點requestManager.track
。
5.requestManager.track
// 2.追蹤Request
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
// -->2.1 將target保存到targetTracker中
this.targetTracker.track(target);
// -->2.2 運行請求
this.requestTracker.runRequest(request);
}
// 2.1 @TargetTracker.java
private final Set<Target<?>> targets = Collections.newSetFromMap(new WeakHashMap());
public void track(@NonNull Target<?> target) {
將tartget加入set中
this.targets.add(target);
}
// 2.2 @RequestTracker.java
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap());
private final List<Request> pendingRequests = new ArrayList();
public void runRequest(@NonNull Request request) {
this.requests.add(request);
if (!this.isPaused) {
// -->2.3調用SingleRequest.begin()方法開始請求
request.begin();
} else {
request.clear();
if (Log.isLoggable("RequestTracker", 2)) {
Log.v("RequestTracker", "Paused, delaying request");
}
//如果是暫停狀態,將請求加入pending隊列中
this.pendingRequests.add(request);
}
}
// 2.3 開始請求 @SingleRequest.java
public void begin() {
synchronized(this.requestLock) {
......
if (Util.isValidDimensions(this.overrideWidth, this.overrideHeight)) {
// -->2.4 請求開始
this.onSizeReady(this.overrideWidth, this.overrideHeight);
} else {
// -->2.5 如果沒有override()方法設置固定寬高,根據imageView寬高計算圖片寬高
this.target.getSize(this);
}
......
}
}
// 2.4 @SingleRequest
public void onSizeReady(int width, int height) {
......
// -->2.6 通過引擎加載, 倒數第二個參數,傳入回調,會砸4.7中用到
this.loadStatus = this.engine.load(this.glideContext, this.model, this.requestOptions.getSignature(), this.width, this.height, this.requestOptions.getResourceClass(), this.transcodeClass, this.priority, this.requestOptions.getDiskCacheStrategy(), this.requestOptions.getTransformations(), this.requestOptions.isTransformationRequired(), this.requestOptions.isScaleOnlyOrNoTransform(), this.requestOptions.getOptions(), this.requestOptions.isMemoryCacheable(), this.requestOptions.getUseUnlimitedSourceGeneratorsPool(), this.requestOptions.getUseAnimationPool(), this.requestOptions.getOnlyRetrieveFromCache(), this, this.callbackExecutor);
......
}
// 2.5 計算圖片寬高 @ViewTarget.java
void getSize(@NonNull SizeReadyCallback cb) {
......
//計算完圖片寬高,最終回調2.4SingleRequest.onSizeReady方法
cb.onSizeReady(currentWidth, currentHeight);
......
}
// 2.6 通過引擎加載 @Engine.java
public <R> Engine.LoadStatus load(...) {
synchronized(this) {
// -->2.7 加載緩存
memoryResource = this.loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
// -->2.8 沒緩存,加載網絡資源
return this.waitForExistingOrStartNewJob(...);
}
}
// 回到到singleRequest類中
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
// 2.7 加載緩存 @Engine.java
@Nullable
private EngineResource<?> loadFromMemory(EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
// 如果設置爲不使用緩存,直接返回
return null;
} else {
// 首先,在弱引用緩存map中查找,找到就直接返回active
EngineResource<?> active = this.loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
} else {
// 接着在內存memoryCache中尋找,找到就直接返回cache
// memoryCache在GlideBuilder.build中初始化,爲LruResourceCache上文有相關代碼
EngineResource<?> cached = this.loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
} else {
return null;
}
}
}
}
//2.8 沒緩存,加載網絡資源 @Engine.java
private <R> Engine.LoadStatus waitForExistingOrStartNewJob(...) {
EngineJob<?> current = this.jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new Engine.LoadStatus(cb, current);
} else {
// 創建下載工程任務類
EngineJob<R> engineJob = this.engineJobFactory.build(key, isMemoryCacheable, useUnlimitedSourceExecutorPool, useAnimationPool, onlyRetrieveFromCache);
// 創建解析工作對象
DecodeJob<R> decodeJob = this.decodeJobFactory.build(glideContext, model, key, signature, width, height, resourceClass, transcodeClass, priority, diskCacheStrategy, transformations, isTransformationRequired, isScaleOnlyOrNoTransform, onlyRetrieveFromCache, options, engineJob);
// 存入Jobs內部維護的HashMap中
this.jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
// -->2.9 啓動請求線程
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new Engine.LoadStatus(cb, engineJob);
}
}
// 2.9 啓動請求線程, 根據配置不同,使用不同的解碼線程池 @Engine.java
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache() ? this.diskCacheExecutor : this.getActiveSourceExecutor();
// -->2.10 啓動解碼任務
executor.execute(decodeJob);
}
// 2.10 啓動解碼任務 @DecodeJob.java
public void run() {
......
try {
if (!this.isCancelled) {
// -->2.11 運行解碼任務
this.runWrapped();
return;
}
......
}
//2.11 運行解碼任務 @DecodeJob.java
private void runWrapped() {
switch(this.runReason) {
case INITIALIZE:
// -->2.12 根據緩存策略生成對應stage,stage的推進就代表緩存的查找順序
this.stage = this.getNextStage(DecodeJob.Stage.INITIALIZE);
// -->2.13 根據stage生成Generator
this.currentGenerator = this.getNextGenerator();
// -->2.14 執行Generator的startNext()方法
this.runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
this.runGenerators();
break;
case DECODE_DATA:
this.decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + this.runReason);
}
}
//2.12 根據緩存策略生成對應stage @DecodeJob.java
private DecodeJob.Stage getNextStage(DecodeJob.Stage current) {
switch(current) {
case RESOURCE_CACHE: //如果支持原圖尺寸,下一個state就是DATA_CACHE,否則,從DATA_CACHE開始往下判斷
return this.diskCacheStrategy.decodeCachedData() ? DecodeJob.Stage.DATA_CACHE : this.getNextStage(DecodeJob.Stage.DATA_CACHE);
case DATA_CACHE: //如果只讀緩存,下一個Stage爲FINISHED,否則就是SOURCE
return this.onlyRetrieveFromCache ? DecodeJob.Stage.FINISHED : DecodeJob.Stage.SOURCE;
case SOURCE:
case FINISHED:
return DecodeJob.Stage.FINISHED;
case INITIALIZE: //如果支持多尺寸,下一個state就是RESOURCE_CACHE,否則,從RESOURCE_CACHE開始往下判斷
return this.diskCacheStrategy.decodeCachedResource() ? DecodeJob.Stage.RESOURCE_CACHE : this.getNextStage(DecodeJob.Stage.RESOURCE_CACHE);
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
// 2.13 根據stage獲取Generator @DecodeJob.java
private DataFetcherGenerator getNextGenerator() {
switch(this.stage) {
case RESOURCE_CACHE: //緩存多尺寸
return new ResourceCacheGenerator(this.decodeHelper, this);
case DATA_CACHE: //緩存原圖
return new DataCacheGenerator(this.decodeHelper, this);
case SOURCE: //下載遠程圖片
return new SourceGenerator(this.decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + this.stage);
}
}
//2.14 循環執行Generators的startNext()方法 @DecodeJob.java
private void runGenerators() {
......
while(!this.isCancelled && this.currentGenerator != null && !(isStarted = this.currentGenerator.startNext())) { //--> 2.15 執行Generator的startNext()方法
//獲取下一個stage
this.stage = this.getNextStage(this.stage);
//獲取下一個Generator
this.currentGenerator = this.getNextGenerator();
if (this.stage == DecodeJob.Stage.SOURCE) {
this.reschedule();
return;
}
}
......
}
// 2.15 以SourceGenerator爲例,@SourceGenerator
public boolean startNext() {
......
boolean started = false;
while(!started && this.hasNextModelLoader()) {
this.loadData = (LoadData)this.helper.getLoadData().get(this.loadDataListIndex++);
// 根據緩存策略來篩選loaddata,這裏最終獲取的loaddata是HttpGlideUrlLoader,Fetcher是HttpUrlFetcher
if (this.loadData != null && (this.helper.getDiskCacheStrategy().isDataCacheable(this.loadData.fetcher.getDataSource()) || this.helper.hasLoadPath(this.loadData.fetcher.getDataClass()))) {
started = true;
// -->2.16 加載數據
this.startNextLoad(this.loadData);
}
}
return started;
}
// 2.16 加載數據 @SourceGenerator.java
private void startNextLoad(final LoadData<?> toStart) {
// -->2.17通過loadData方法獲取圖片數據
this.loadData.fetcher.loadData(this.helper.getPriority(), new DataCallback<Object>() {this.helper.getPriority(), new DataCallback<Object>() {
public void onDataReady(@Nullable Object data) {
if (SourceGenerator.this.isCurrentRequest(toStart)) {
// -->3.1 獲取數據之後回調數據到SourceGenerator進行解碼
SourceGenerator.this.onDataReadyInternal(toStart, data);
}
}
......
}
}
// 2.17 獲取圖片數據 @HttpUrlFetcher.java
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
......
try {
// -->2.18 網絡下載圖片
InputStream result = this.loadDataWithRedirects(this.glideUrl.toURL(), 0, (URL)null, this.glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException var9) {...}
......
}
// 2.18 使用HttpURLConnection下載網絡圖片 @HttpUrlFetcher.java
private InputStream loadDataWithRedirects(...) throws IOException {
if (redirects >= 5) {
//設置最大重定向次數爲5次
throw new HttpException("Too many (> 5) redirects!");
} else {
......
this.urlConnection.setConnectTimeout(this.timeout);
this.urlConnection.setReadTimeout(this.timeout);
this.urlConnection.setUseCaches(false);
this.urlConnection.setDoInput(true);
this.urlConnection.setInstanceFollowRedirects(false);
this.urlConnection.connect();
this.stream = this.urlConnection.getInputStream();
if (this.isCancelled) {
return null;
} else {
int statusCode = this.urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
// -->2.19請求成功,獲取圖片數據
return this.getStreamForSuccessfulRequest(this.urlConnection);
} else if (isHttpRedirect(statusCode)) {
......
// 重定向次數加1
return this.loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
}
} else if (statusCode == -1) {
throw new HttpException(statusCode);
} else {
throw new HttpException(this.urlConnection.getResponseMessage(), statusCode);
}
}
}
}
// 2.19 獲取數據流 @HttpUrlFetcher.java
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection) throws IOException {
if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
int contentLength = urlConnection.getContentLength();
this.stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), (long)contentLength);
} else {
if (Log.isLoggable("HttpUrlFetcher", 3)) {
Log.d("HttpUrlFetcher", "Got non empty content encoding: " + urlConnection.getContentEncoding());
}
// 獲取數據流
this.stream = urlConnection.getInputStream();
}
return this.stream;
}
終於到了圖篇下載的地方,我們最後獲取的是數據流,接下來的步驟是數據流解碼。
6.返回數據流解碼
// -->3.1 返回數據流到SourceGenerator @SourceGenerator.java
void onDataReadyInternal(LoadData<?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = this.helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
this.dataToCache = data;
this.cb.reschedule();
} else {
// --> 3.2 回到DecodeJob繼續處理,會調用到decodeFromRetrievedData處理
this.cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher, loadData.fetcher.getDataSource(), this.originalKey);
}
}
// 3.2 處理返回數據 @DecodeJob.java
private void decodeFromRetrievedData() {
......
try {
// -->3.3 在decodeFromFetcher中調用decodeFromFetcher處理,從數據中解碼得到資源
resource = this.decodeFromData(this.currentFetcher, this.currentData, this.currentDataSource);
} catch (GlideException var3) {
var3.setLoggingDetails(this.currentAttemptingKey, this.currentDataSource);
this.throwables.add(var3);
}
if (resource != null) {
// -->4.1 編碼和發佈資源
this.notifyEncodeAndRelease(resource, this.currentDataSource);
} else {
this.runGenerators();
}
}
// 3.3 @DecodeJob.java
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource) throws GlideException {
LoadPath<Data, ?, R> path = this.decodeHelper.getLoadPath(data.getClass());
// -->3.4 將解碼任務分發給LoadPath
return this.runLoadPath(data, dataSource, path);
}
// 3.4 將解碼任務分發給LoadPath
private <Data, ResourceType> Resource<R> runLoadPath(...) throws GlideException {
Options options = this.getOptionsWithHardwareConfig(dataSource);
// 將數據打包到Rewinder對象中,根據data的類型獲取對應的rewinder,這裏爲ByteBufferRewinder
DataRewinder rewinder = this.glideContext.getRegistry().getRewinder(data);
Resource var6;
try {
// -->3.5 LoadPath.load -> LoadPath.loadWithExceptionList -> DecodePath.decodeResource ->
// DecodePath.decodeResourceWithList
var6 = path.load(rewinder, options, this.width, this.height, new DecodeJob.DecodeCallback(dataSource));
} finally {
rewinder.cleanup();
}
return var6;
}
// 3.5 @DecodePath.java
private Resource<ResourceType> decodeResourceWithList(...) throws GlideException {
......
try {
DataType data = rewinder.rewindAndGet();
if (decoder.handles(data, options)) {
data = rewinder.rewindAndGet();
// -->3.6根據dataType使用對應的decoder,這裏decoder是ByteBufferBitmapDecoder
result = decoder.decode(data, width, height, options);
}
}
......
if (result == null) {
// 如果找不到合適的decoder拋出異常,回到LoadPath.loadWithExceptionList中用下一個DecodePath處理
throw new GlideException(this.failureMessage, new ArrayList(exceptions));
} else {
return result;
}
}
// 3.6 對數據進行處理 @ByteBufferBitmapDecoder.java
public Resource<Bitmap> decode(...) throws IOException {
InputStream is = ByteBufferUtil.toStream(source);
// -->3.7 使用downsampler對流數據進行解碼和圖像處理等,並封裝爲Resource<Bitmap>對象返回
return this.downsampler.decode(is, width, height, options);
}
// 3.7 使用downsampler對流數據進行解碼和圖像處理等 @Downsampler.java
private Resource<Bitmap> decode(...) throws IOException {
BitmapResource var14;
try {
//Bitmap處理
Bitmap result = this.decodeFromWrappedStreams(imageReader, bitmapFactoryOptions, downsampleStrategy, decodeFormat, preferredColorSpace, isHardwareConfigAllowed, requestedWidth, requestedHeight, fixBitmapToRequestedDimensions, callbacks);
//打包爲Resource<Bitmap>對象返回
var14 = BitmapResource.obtain(result, this.bitmapPool);
} finally {
releaseOptions(bitmapFactoryOptions);
this.byteArrayPool.put(bytesForOptions);
}
return var14;
}
通過上面步驟,基本解碼流程就結束了,加下來進入解碼和發佈流程
7.解碼和發佈
解碼和發佈,就是將Bitmap顯示到ImageView,這裏的入口在notifyEncodeAndRelease中,代碼回到DecodeJob中。
// 4.1 解碼和發佈流程入口 @DecodeJob.java
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
......
// -->4.2 開始解碼和發佈
this.notifyComplete((Resource)result, dataSource);
// 設置stage爲ENCODE
this.stage = DecodeJob.Stage.ENCODE;
......
}
//4.2 開始解碼和發佈 @DecodeJob.java
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
this.setNotifiedOrThrow();
// -->4.3 回調EngineJob.onResourceReady
this.callback.onResourceReady(resource, dataSource);
}
// 4.3 @EngineJob.java
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized(this) {
this.resource = resource;
this.dataSource = dataSource;
}
// -->4.4
this.notifyCallbacksOfResult();
}
// 4.4 @EngineJob.java
void notifyCallbacksOfResult() {
......
// -->4.5
while(var4.hasNext()) {
EngineJob.ResourceCallbackAndExecutor entry = (EngineJob.ResourceCallbackAndExecutor)var4.next();
entry.executor.execute(new EngineJob.CallResourceReady(entry.cb));
}
}
//4.5 @EngineJob.java
static final class ResourceCallbackAndExecutor {
while(var4.hasNext()) {
EngineJob.ResourceCallbackAndExecutor entry = (EngineJob.ResourceCallbackAndExecutor)var4.next();
entry.executor.execute(new EngineJob.CallResourceReady(entry.cb)); //-->4.6
}
}
//4.6 @EngineJob.java
private class CallResourceReady implements Runnable {
public void run() {
......
// -->4.7
EngineJob.this.callCallbackOnResourceReady(this.cb);
......
}
}
//4.7 @EngineJob.java
void callCallbackOnResourceReady(ResourceCallback cb) {
try {
//-->4.8 這裏的回調cb指的傳的就是SingleRequest,在2.6中 SingleRequest中把自身作爲倒數第二個參數傳入engine.load中
cb.onResourceReady(this.engineResource, this.dataSource);
} catch (Throwable var3) {
throw new CallbackException(var3);
}
}
// 4.8 @SingleRequest.java
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
......
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
//-->4.9 這裏的target便是我們調用之初建立的BitmapImageViewTarget,具體的實現方法在其父類ImageViewTarget中
target.onResourceReady(result, animation);
}
......
}
// 4.9 @ImageViewTarget.java
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource); //-->4.10
} else {
maybeUpdateAnimatable(resource);
}
}
//4.10 @ImageViewTarget.java
private void setResourceInternal(@Nullable Z resource) {
//-->4.11 抽象方法,具體實現在子類BitmapImageViewTarget中
setResource(resource);
maybeUpdateAnimatable(resource);
}
//4.11 @BitmapImageView.java
@Override
protected void setResource(Bitmap resource) {
//終於看到了Bitmap設置到imageView上!
view.setImageBitmap(resource);
}
從上面分析流程可知,Gilde大多數的處理流程都在into
方法中執行,請求,數據,編碼解碼,以及最後的顯示,這份源碼值得我們多讀幾次,細細品味。
文章雖然很長,但是我還是決定不分篇,以保證加載流程閱讀的完整度,也方便後期檢索方便。很感謝看到最後的各位~