Glide的常用方式:
Glide.with(this).load(url).into(iv);
通過這一幾個鏈式調用的方法就完成了從網絡上加載一個圖片在本地顯示的功能,下面分析一下,內部的具體實現邏輯:
with()方法
首先看看Glide.with()方法:
public class Glide {
...
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
...
}
這個方法返回了一個RequestManager類型的對象。後面的load方法就是調用的RequestManager類的
load方法,下面看看這個方法的具體實現:
public class RequestManager implements LifecycleListener {
...
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString() //關鍵代碼1
.load(string); // 關鍵代碼2
}
...
public DrawableTypeRequest<String> fromString() {
//關鍵代碼3
return loadGeneric(String.class);
}
private <T> DrawableTypeRequest<T> loadGeneric(Class<T> modelClass) {
//關鍵代碼4
ModelLoader<T, InputStream> streamModelLoader = Glide.buildStreamModelLoader(modelClass, context);
//關鍵代碼5
ModelLoader<T, ParcelFileDescriptor> fileDescriptorModelLoader =
Glide.buildFileDescriptorModelLoader(modelClass, context);
if (modelClass != null && streamModelLoader == null && fileDescriptorModelLoader == null) {
throw new IllegalArgumentException("Unknown type " + modelClass + ". You must provide a Model of a type for"
+ " which there is a registered ModelLoader, if you are using a custom model, you must first call"
+ " Glide#register with a ModelLoaderFactory for your custom model class");
}
return optionsApplier.apply(
//關鍵代碼6,,注意,這裏的modelClass是String.class
new DrawableTypeRequest<T>(modelClass, streamModelLoader, fileDescriptorModelLoader, context,
glide, requestTracker, lifecycle, optionsApplier));
}
class OptionsApplier {
public <A, X extends GenericRequestBuilder<A, ?, ?, ?>> X apply(X builder) {
//關鍵代碼7
if (options != null) {
options.apply(builder);
}
return builder;
}
}
...
}
load()方法
在RequestManager類的load方法中,做了如下幾件事:
1.在關鍵代碼1處,調用了fromString()方法,接着調用了關鍵代碼3處的loadGeneric方法,在接着在關鍵代碼4創建了ModelLoader類型的streamModelLoader對象,下面看看這個streamModelLoader具體是什麼ModelLoader的哪個子類型的對象:
public class Glide {
...
public static <T> ModelLoader<T, InputStream> buildStreamModelLoader(Class<T> modelClass, Context context) {
return buildModelLoader(modelClass, InputStream.class, context);
}
...
public static <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
Context context) {
if (modelClass == null) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Unable to load null model, setting placeholder only");
}
return null;
}
//關鍵代碼處
return Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass);
}
...
}
這個方法內部調用了buildModelLoader,在關鍵代碼處,調用了Glide.get(context).getLoaderFactory()生成了GenericLoaderFactory類型的對象,然後調用了GenericLoaderFactory類的buildModelLoader方法:
public class GenericLoaderFactory {
...
@Deprecated
public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass,
Context context) {
return buildModelLoader(modelClass, resourceClass);
}
public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
...
//關鍵代碼1
final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
if (factory != null) {
//關鍵代碼2
result = factory.build(context, this);
cacheModelLoader(modelClass, resourceClass, result);
}
...
return result;
}
...
private <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) {
Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
ModelLoaderFactory/*T, Y*/ result = null;
if (resourceToFactories != null) {
result = resourceToFactories.get(resourceClass);
}
if (result == null) {
for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) {
if (registeredModelClass.isAssignableFrom(modelClass)) {
Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> currentResourceToFactories =
modelClassToResourceFactories.get(registeredModelClass);
if (currentResourceToFactories != null) {
result = currentResourceToFactories.get(resourceClass);
if (result != null) {
break;
}
}
}
}
}
return result;
}
...
}
下面先分析關鍵代碼1處,調用了getFactory方法,傳入的參數就是String.class和InputStream.class。
在上面的getFactory方法中,是根據String.class這個key從modelClassToResourceFactories這個hashMap獲取到期對應的value的,這個獲取的value是一個HashMap,在繼續向下分析之前,需要搞清楚,這個modelClassToResourceFactories是在哪裏存放key和value的,其實是在Glide類的初始化的時候存入的。下面看看和本例相關的部分的Glide初始化的部分代碼:
public class Glide {
...
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
...
//關鍵代碼1處,這裏register()方法傳入的參數分別是Sring.class,InputStream.class和StreamStringLoader.Factory對象
register(String.class, InputStream.class, new StreamStringLoader.Factory());
register(Uri.class, ParcelFileDescriptor.class, new FileDescriptorUriLoader.Factory());
register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
register(URL.class, InputStream.class, new StreamUrlLoader.Factory());
register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
}
...
public <T, Y> void register(Class<T> modelClass, Class<Y> resourceClass, ModelLoaderFactory<T, Y> factory) {
ModelLoaderFactory<T, Y> removed = loaderFactory.register(modelClass, resourceClass, factory);
if (removed != null) {
removed.teardown();
}
}
...
}
在關鍵代碼1處,通過register方法,將String.class作爲key,StreamStringLoader.Factory()對象作爲value,存入到GenericLoaderFactory類的modelClassToResourceFactories這個hashMap中。在回到GenericLoaderFactory類的buildModelLoader方法,可以知道這個方法中的getFactory獲取的其實就是StreamStringLoader.Factory()對象,在繼續看GenericLoaderFactory類的buildModelLoader方法的關鍵代碼2處,通過factory.build方法來獲取ModelLoader類型的對象,下面看看StreamStringLoader.Factory類的build方法的具體實現:
public class StreamStringLoader extends StringLoader<InputStream> implements StreamModelLoader<String> {
/**
* The default factory for {@link com.bumptech.glide.load.model.stream.StreamStringLoader}s.
*/
public static class Factory implements ModelLoaderFactory<String, InputStream> {
@Override
public ModelLoader<String, InputStream> build(Context context, GenericLoaderFactory factories) {
return new StreamStringLoader(factories.buildModelLoader(Uri.class, InputStream.class));
}
@Override
public void teardown() {
// Do nothing.
}
}
...
}
這個方法內部,返回的是一個StreamStringLoader類型的對象。到這裏弄清楚了Glide.buildStreamModelLoader(modelClass, context);這行代碼返回的是StreamStringLoader類型的對象。到這裏在RequestManager類的load方法中關鍵代碼1處的代碼分析完畢。
2.在RequestManager類的load方法中,關鍵代碼5處,創建了ModelLoader類型的fileDescriptorModelLoader對象。
3.在在RequestManager類的load方法中,關鍵代碼6處調用OptionsApplier類型的對象的apply方法,這個方法內部創建了一個DrawableTypeRequest對象,下面看看DrawableTypeRequest的構造方法:
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
...
DrawableTypeRequest(Class<ModelType> modelClass, ModelLoader<ModelType, InputStream> streamModelLoader,
ModelLoader<ModelType, ParcelFileDescriptor> fileDescriptorModelLoader, Context context, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle, RequestManager.OptionsApplier optionsApplier) {
//關鍵代碼1,這裏的modelClass是String.class
super(context, modelClass,
//關鍵代碼2
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null),
glide, requestTracker, lifecycle);
this.streamModelLoader = streamModelLoader;
this.fileDescriptorModelLoader = fileDescriptorModelLoader;
this.optionsApplier = optionsApplier;
}
...
}
這個構造方法內部在關鍵代碼1處調用了其父類DrawableRequestBuilder的構造方法:
public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
DrawableRequestBuilder(Context context, Class<ModelType> modelClass,
LoadProvider<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable> loadProvider, Glide glide,
RequestTracker requestTracker, Lifecycle lifecycle) {
//關鍵代碼,第二個參數是String.class,第四個參數是GlideDrawable.class
super(context, modelClass, loadProvider, GlideDrawable.class, glide, requestTracker, lifecycle);
// Default to animating.
crossFade();
}
...
}
在這個方法內部的關鍵代碼處,調用了DrawableRequestBuilder的父類GenericRequestBuilder的構造方法,注意傳入其父類的構造方法的第一個參數是String.classs,第四個參數是GlideDrawable.class。這裏先記錄下來,後面要用到這個參數。在回到DrawableTypeRequest的構造方法的關鍵代碼2處,調用了
buildProvider(glide, streamModelLoader, fileDescriptorModelLoader, GifBitmapWrapper.class,
GlideDrawable.class, null)
下面看看這個方法的具體實現(注意,傳入的第二個參數streamModelLoader就是前面分析過的StreamStringLoader類型的對象,第四個參數是GifBitmapWrapper.class,第五個參數是GlideDrawable.class):
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
...
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
if (streamModelLoader == null && fileDescriptorModelLoader == null) {
return null;
}
if (transcoder == null) {
transcoder = glide.buildTranscoder(resourceClass, transcodedClass);
}
//關鍵代碼1,resourceClass就是GifBitmapWrapper.class
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
//關鍵代碼2,treamModelLoader就是前面分析過的StreamStringLoader類型的對象
ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
fileDescriptorModelLoader);
//關鍵代碼3,modelLoader就是ImageVideoModelLoader,dataLoadProvider就是ImageVideoGifDrawableLoadProvider
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
}
...
在這個方法中的關鍵代碼1處,通過Glide類的buildDataProvider()方法,創建了一個DataLoadProvider類型的對象,下面看看這個方法的具體實現:
public class Glide {
...
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
dataLoadProviderRegistry = new DataLoadProviderRegistry();
...
dataLoadProviderRegistry = new DataLoadProviderRegistry();
StreamBitmapDataLoadProvider streamBitmapLoadProvider =
new StreamBitmapDataLoadProvider(bitmapPool, decodeFormat);
dataLoadProviderRegistry.register(InputStream.class, Bitmap.class, streamBitmapLoadProvider);
FileDescriptorBitmapDataLoadProvider fileDescriptorLoadProvider =
new FileDescriptorBitmapDataLoadProvider(bitmapPool, decodeFormat);
dataLoadProviderRegistry.register(ParcelFileDescriptor.class, Bitmap.class, fileDescriptorLoadProvider);
ImageVideoDataLoadProvider imageVideoDataLoadProvider =
new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
dataLoadProviderRegistry.register(ImageVideoWrapper.class, Bitmap.class, imageVideoDataLoadProvider);
GifDrawableLoadProvider gifDrawableLoadProvider =
new GifDrawableLoadProvider(context, bitmapPool);
dataLoadProviderRegistry.register(InputStream.class, GifDrawable.class, gifDrawableLoadProvider);
//關鍵代碼2
dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));
dataLoadProviderRegistry.register(InputStream.class, File.class, new StreamFileDataLoadProvider());
}
<T, Z> DataLoadProvider<T, Z> buildDataProvider(Class<T> dataClass, Class<Z> decodedClass) {
//關鍵代碼1,dataClass就是ImageVideoWrapper.class,decodedClass就是GifBitmapWrapper.class
return dataLoadProviderRegistry.get(dataClass, decodedClass);
}
}
Glide類的buildDataProvider()方法內部是通過dataLoadProviderRegistry這個變量的get方法,get方法內部其實是通過一個hashMap,根據傳入的參數來獲取相應的DataLoadProvider,而這個hashMap是在Glide類初始化時,就已經存入了很多的key和value,在上面的代碼中的關鍵代碼2處,可以看到,dataLoadProviderRegistry對象調用了
register方法,register方法內部,通過hashMap來將ImageVideWrapper.class和GifBitmapWrapper.class兩個變量通合成爲一個key,ImageVideoGifDrawableLoadProvider作爲value存儲,這樣存儲起來。而dataLoadProviderRegistry.get()方法中獲取DataLoadProvider對象是,傳入的參數正好是ImageVideoWrapper.class和GifBitmapWrapper.class,所以dataLoadProviderRegistry.get()方法返回的就是ImageVideoGifDrawableLoadProvider類型的對象。分析到這裏,弄清楚了DrawableTypeRequest構造函數的關鍵代碼1處的,
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
...
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
...
//關鍵代碼1,resourceClass就是GifBitmapWrapper.class
DataLoadProvider<ImageVideoWrapper, Z> dataLoadProvider = glide.buildDataProvider(ImageVideoWrapper.class,
resourceClass);
...
}
...
dataLoadProvider 其實就是ImageVideoGifDrawableLoadProvider類型的對象。這個對象在後面會用到。
下面繼續分析DrawableTypeRequest構造函數的關鍵代碼2處的代碼:
public class DrawableTypeRequest<ModelType> extends DrawableRequestBuilder<ModelType> implements DownloadOptions {
...
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
...
//關鍵代碼2,treamModelLoader就是前面分析過的StreamStringLoader類型的對象
ImageVideoModelLoader<A> modelLoader = new ImageVideoModelLoader<A>(streamModelLoader,
fileDescriptorModelLoader);
...
}
在關鍵代碼2處,這裏構建一個ImageVideoModelLoader類型的對象,要注意傳入ImageVideoModelLoader的構造函數中的streamModelLoader是StreamStringLoader類型的對象,至於ImageVideoModelLoader的構造函數中的初始化操作,後面會分析到,並且會用到StreamStringLoader類型的對象,這裏只是強調一下。
下面繼續分析DrawableTypeRequest構造函數的關鍵代碼3處的代碼
...
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
...
//關鍵代碼3
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
...
}
在關鍵代碼3處創建了一個FixedLoadProvider對象,注意傳入的參數modelLoader就是ImageVideoModelLoader類型的對象,dataLoadProvider進過前面的分析可以知道就是ImageVideoGifDrawableLoadProvider類型的對象。
下面繼續分析RequestManager類的load方法的關鍵代碼6處,OptionsApplier類是RequestManager類的一個內部類,調用apply方法後,在關鍵代碼7處,由於未給options賦值,這裏options是爲null的,所以直接返回傳入的參數,也就是DrawableTypeRequest類型的對象。在關鍵代碼2處,調用了DrawableTypeRequest的load方法,下面看看這個方法的具體實現:
public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
...
@Override
public DrawableRequestBuilder<ModelType> load(ModelType model) {
super.load(model);
return this;
}
...
}
這個方法內部調用了其父類的load方法,下面看看父類GenericRequestBuilder的load方法
public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
...
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
...
}
GenericRequestBuilder類的load方法也僅僅是將傳入的圖片地址進行了保存.。到這裏,分析完了Glide,with(this).load(url)這部分的鏈式調用的代碼邏輯。
into()方法
下面繼續看Glide,with(this).load(url).into(iv)這個鏈式調用的into方法的具體實現,通過上面的分析可以知道Glide.with(this).load(url)返回的是一個DrawableTypeRequest類型的對象,所以鏈式調用into方法就是調用的DrawableTypeRequest類的into方法,調用的這個into方法是其父類GlideDrawableRequestBuilder的into方法,下面看看這個方法的具體實現:
#DrawableRequestBuilder.java
public class DrawableRequestBuilder<ModelType>
extends GenericRequestBuilder<ModelType, ImageVideoWrapper, GifBitmapWrapper, GlideDrawable>
implements BitmapOptions, DrawableOptions {
...
@Override
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
...
}
這個方法內部調用了其父類GenericRequestBuilder的into方法
public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
...
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
//關鍵代碼1
return into(glide.buildImageViewTarget(view, transcodeClass));
}
}
這個方法內部,調用了另外一個重載的into方法,並通過glide.buildImageViewTarget(view, transcodeClass)創建了一個ViewTarget類型的對象。下面繼續分析glide.buildImageViewTarget(view, transcodeClass)創建了ViewTarget的具體哪種類型的子對象。
#Glide.java
public class Glide {
...
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
...
}
public class ImageViewTargetFactory {
@SuppressWarnings("unchecked")
public <Z> Target<Z> buildTarget(ImageView view, Class<Z> clazz) {
//關鍵代碼
if (GlideDrawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new GlideDrawableImageViewTarget(view);
} else if (Bitmap.class.equals(clazz)) {
return (Target<Z>) new BitmapImageViewTarget(view);
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (Target<Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException("Unhandled class: " + clazz
+ ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
從前面分析的DrawableTypeRequest的構造方法時,在其方法內部調用了其父類的構造方法,傳入其父類的構造方法的第四個參數是GlideDrawable.class,就是
imageViewTargetFactory.buildTarget(imageView, transcodedClass);這個方法內部的第二個參數,即transcoderClass就是GlideDrawable.class。所以,glide.buildImageViewTarget(view, transcodeClass)返回的是一個GlideDrawableImageViewTarget類型的對象,這個對象會到後面分析時用到。下面接着繼續分析
DrawableTypeRequest的父類GenericRequestBuilder的into方法內部調用的其重載方法:
public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
...
public <Y extends Target<TranscodeType>> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
Request previous = target.getRequest();
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
//關鍵代碼1
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
//關鍵代碼2
requestTracker.runRequest(request);
return target;
}
...
private Request buildRequest(Target<TranscodeType> target) {
if (priority == null) {
priority = Priority.NORMAL;
}
return buildRequestRecursive(target, null);
}
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
if (thumbnailRequestBuilder != null) {
...
return coordinator;
} else if (thumbSizeMultiplier != null) {
...
return coordinator;
} else {
// Base case: no thumbnail.
//關鍵代碼
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
}
private Request obtainRequest(Target<TranscodeType> target, float sizeMultiplier, Priority priority,
RequestCoordinator requestCoordinator) {
return GenericRequest.obtain(
loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderId,
errorPlaceholder,
errorId,
fallbackDrawable,
fallbackResource,
requestListener,
requestCoordinator,
glide.getEngine(),
transformation,
transcodeClass,
isCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
}
}
在關鍵代碼1處調用了buildRequest方法,這個方法內部又調用了buildRequestRecursive()方法,buildRequestRecursive()方法內部,由於未使用縮略圖,所以前面兩個if判斷都不成立,會調用obtainRequest方法,最後調用到了GenericRequest.obtain()方法。GenericRequest.obtain()方法內部會根據傳入的參數對GenericRequest的成員變量進行初始化,這裏特別要注意,給GenericRequest進行初始化時,傳入的target其實就是前面分析過的GlideDrawableImageViewTarget類型的對象。後面會用到這個參數。這裏在次強調一下,便於讀者加深映像。GenericRequest.obtain()方法返回的是GenericRequest類型的對象。所以前面調用的buidlRequest()方法返回的是GenericRequest類型的對象。後面會立刻用到這個對象。在次回到GenericRequestBuilder類的into方法,在關鍵代碼2處,調用了
public class GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> implements Cloneable {
...
public <Y extends Target<TranscodeType>> Y into(Y target) {
...
//關鍵代碼2
requestTracker.runRequest(request);
return target;
}
這行代碼調用了RequestTracker 類的runRequest方法
public class RequestTracker {
...
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
//關鍵代碼
request.begin();
} else {
pendingRequests.add(request);
}
}
...
}
這個方法內部調用了request.begin()方法,經過前面的分析可以知道,這個request就是GenericRequest類型的對象。這樣代碼就執行到了GenericRequest類的begin方法中了:
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,ResourceCallback {
...
@Override
public void begin() {
startTime = LogTime.getLogTime();
if (model == null) {
//關鍵代碼1
onException(null);
return;
}
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//關鍵代碼2
onSizeReady(overrideWidth, overrideHeight);
} else {
//關鍵代碼3
target.getSize(this);
}
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
//關鍵代碼4
target.onLoadStarted(getPlaceholderDrawable());
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
}
這個方法中,下面分別分析4個關鍵代碼處的代碼,
在關鍵代碼1處,如果model爲null:
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,ResourceCallback {
@Override
public void onException(Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "load failed", e);
}
status = Status.FAILED;
//TODO: what if this is a thumbnail request?
if (requestListener == null || !requestListener.onException(e, model, target, isFirstReadyResource())) {
setErrorPlaceholder(e);
}
}
...
private void setErrorPlaceholder(Exception e) {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = model == null ? getFallbackDrawable() : null;
if (error == null) {
error = getErrorDrawable();
}
if (error == null) {
error = getPlaceholderDrawable();
}
//關鍵代碼
target.onLoadFailed(e, error);
}
...
}
這個方法內部會調用到 target.onLoadFailed(e, error);這裏的target前面已經多次強調過是GlideDrawableImageViewTarget類型的對象。所以代碼跳轉到了GlideDrawableImageViewTarget類的onLoadFailed(e, error)方法,由於GlideDrawableImageViewTarget類沒有這個方法,發現是其父類的方法
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
...
}
從這個方法可以看出,如果請求失敗,會調用傳入的ImageView的setImageDrawable(errorDrawable)方法將錯誤圖片顯示出來。
下面繼續分析GenericRequest類的begin方法中關鍵2處和關鍵3處的代碼,通過分析,無論是走關鍵2還是關鍵3處的邏輯,都會調用到onSizeReady方法,下面看看這個方法的具體實現:
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback, ResourceCallback {
@Override
public void onSizeReady(int width, int height) {
...
//關鍵代碼1,這裏的loadProvider其實就是FixedLoadProvider對象
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
//關鍵代碼2
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
//關鍵代碼3
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
...
}
}
在這個方法的關鍵代碼1處,調用了loadProvider.getModelLoader()方法,這裏的loadProvider是在GenericRequest的初始化賦值的,在前面的分析知道,這裏的 loadProvider其實就是FixedLoadProvider類型的對象。這樣loadProvider.getModelLoader()執行的就是FixedLoadProvider類的getModelLoader()方法,下面看看這個方法:
public class FixedLoadProvider<A, T, Z, R> implements LoadProvider<A, T, Z, R> {
...
@Override
public ModelLoader<A, T> getModelLoader() {
return modelLoader;
}
...
}
這個方法內部就是返回了一個FixedLoadProvider類的成員變量modelLoader,在前面分析FixedLoadProvider類初始化時,就已經強調過,傳入FixedLoadProvider類的構造函數的這個modelLoader是是ImageVideoModelLoader類型的對象,所以loadProvider.getModelLoader()方法返回的就是ImageVideoModelLoader類型的對象。在繼續分析GenericRequest類的onSizeReady()方法的關鍵代碼2處的代碼:
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback, ResourceCallback {
@Override
public void onSizeReady(int width, int height) {
...
//關鍵代碼1,這裏的loadProvider其實就是FixedLoadProvider對象
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
//關鍵代碼2
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
...
}
}
前面已經分析過關鍵代碼1處的modelLoader 其實就是ImageVideoModelLoader類型的對象,在關鍵代碼2處,就是調用的ImageVideoModelLoader類的getResourceFetcher()方法。下面看看這個方法的具體實現:
public class ImageVideoModelLoader<A> implements ModelLoader<A, ImageVideoWrapper> {
@Override
public DataFetcher<ImageVideoWrapper> getResourceFetcher(A model, int width, int height) {
DataFetcher<InputStream> streamFetcher = null;
if (streamLoader != null) {
//關鍵代碼1
streamFetcher = streamLoader.getResourceFetcher(model, width, height);
}
DataFetcher<ParcelFileDescriptor> fileDescriptorFetcher = null;
if (fileDescriptorLoader != null) {
fileDescriptorFetcher = fileDescriptorLoader.getResourceFetcher(model, width, height);
}
if (streamFetcher != null || fileDescriptorFetcher != null) {
//關鍵代碼2
return new ImageVideoFetcher(streamFetcher, fileDescriptorFetcher);
} else {
return null;
}
}
}
在這個方法的關鍵代碼2處,返回了一個ImageVideoFetcher類型的對象。但是在創建ImageVideoFetcher類型的對象時,傳入的構造函數的第一個參數streamFetcher是在關鍵代碼1處生成的,這個streamFetcher很重要,後面會用到,這裏先分析下,這個streamFetcher究竟是個什麼東東?這個streamFetcher是通過
關鍵代碼1處的streamLoader.getResourceFetcher(model, width, height)方法獲取的,通過前面的分析可以知道這個streamLoader其實就是StreamStringLoader類型的對象,所以,代碼跳轉到了StreamStringLoader類的getResourceFetcher()方法,通過查看源碼發現,getResourceFetcher()方法是StreamStringLoader類的父類StringLoader的方法:
public class StringLoader<T> implements ModelLoader<String, T> {
...
@Override
public DataFetcher<T> getResourceFetcher(String model, int width, int height) {
Uri uri;
if (TextUtils.isEmpty(model)) {
return null;
} else if (model.startsWith("/")) {
uri = toFileUri(model);
} else {
uri = Uri.parse(model);
final String scheme = uri.getScheme();
if (scheme == null) {
uri = toFileUri(model);
}
}
// 關鍵代碼
return uriLoader.getResourceFetcher(uri, width, height);
}
...
}
這個方法內部通過uriLoader的getResourceFetcher()方法來返回一個DataFetcher類型的對象。在繼續往下分析前, 要弄清楚,這個uriLoader是從哪裏來的,前面分析過,StreamStringLoader.Factory類的build方法的具體實現:
public class StreamStringLoader extends StringLoader<InputStream> implements StreamModelLoader<String> {
/**
* The default factory for {@link com.bumptech.glide.load.model.stream.StreamStringLoader}s.
*/
public static class Factory implements ModelLoaderFactory<String, InputStream> {
@Override
public ModelLoader<String, InputStream> build(Context context, GenericLoaderFactory factories) {
return new StreamStringLoader(factories.buildModelLoader(Uri.class, InputStream.class));
}
@Override
public void teardown() {
// Do nothing.
}
}
...
}
這個方法內部調用的StreamStringLoader的構造方法,並通過factories.buildModelLoader(Uri.class, InputStream.class)來給這個uriLoader賦值的,如果弄清楚了factories.buildModelLoader(Uri.class, InputStream.class)這行代碼的邏輯,就能確定uriLoader的值了。下面來分析這行代碼的邏輯,這行代碼調用的是
GenericLoaderFactory 類的buildModelLoader方法,注意,傳入的參數是Uri.class和InputStream.class.
public class GenericLoaderFactory {
...
/**
* Returns a {@link ModelLoader} for the given model and resource classes by either returning a cached
* {@link ModelLoader} or building a new a new {@link ModelLoader} using registered {@link ModelLoaderFactory}s.
* Returns null if no {@link ModelLoaderFactory} is registered for the given classes.
*
* @param modelClass The model class.
* @param resourceClass The resource class.
* @param <T> The type of the model.
* @param <Y> The type of the resource.
*/
public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
if (result != null) {
if (NULL_MODEL_LOADER.equals(result)) {
return null;
} else {
return result;
}
}
//關鍵代碼1
final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
if (factory != null) {
// 關鍵代碼2
result = factory.build(context, this);
cacheModelLoader(modelClass, resourceClass, result);
} else {
// We can't generate a model loader for the given arguments with the currently registered set of factories.
cacheNullLoader(modelClass, resourceClass);
}
return result;
}
...
private <T, Y> ModelLoaderFactory<T, Y> getFactory(Class<T> modelClass, Class<Y> resourceClass) {
Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> resourceToFactories = modelClassToResourceFactories.get(modelClass);
ModelLoaderFactory/*T, Y*/ result = null;
if (resourceToFactories != null) {
result = resourceToFactories.get(resourceClass);
}
if (result == null) {
for (Class<? super T> registeredModelClass : modelClassToResourceFactories.keySet()) {
if (registeredModelClass.isAssignableFrom(modelClass)) {
Map<Class/*Y*/, ModelLoaderFactory/*T, Y*/> currentResourceToFactories =
modelClassToResourceFactories.get(registeredModelClass);
if (currentResourceToFactories != null) {
result = currentResourceToFactories.get(resourceClass);
if (result != null) {
break;
}
}
}
}
}
return result;
}
...
}
在這個方法的關鍵代碼1處,會調用getFactory方法,getFactory方法內部會通過傳入的參數作爲key從modelClassToResourceFactories這個hashMap,中取出相應的value。這裏傳入的key是Uri.class。在繼續分析下去之前,在次看看Glide的初始化:
public class Glide {
...
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
...
//關鍵代碼處,這裏傳入register方法的參數分別是Uri.class,InputStream.class和StreamStringLoader.Factory對象
register(Uri.class, InputStream.class, new StreamUriLoader.Factory());
...
}
...
}
從Glide的初始化調用了register方法,其實就是在將Uri.class作爲key,StreamUriLoader.Factory這個對象作爲value保存到GenericLoaderFactory的modelClassToResourceFactories這個hashMap中,所在上面分析的getFactory方法,傳入的參數是Uri.class時,返回的是StreamUriLoader.Factory這個對象。下面繼續分析GenericLoaderFactory 類的buildModelLoader()方法的關鍵代碼2處
public class GenericLoaderFactory {
...
public synchronized <T, Y> ModelLoader<T, Y> buildModelLoader(Class<T> modelClass, Class<Y> resourceClass) {
ModelLoader<T, Y> result = getCachedLoader(modelClass, resourceClass);
...
//關鍵代碼1
final ModelLoaderFactory<T, Y> factory = getFactory(modelClass, resourceClass);
if (factory != null) {
// 關鍵代碼2
result = factory.build(context, this);
cacheModelLoader(modelClass, resourceClass, result);
}
...
return result;
}
經過前面的分析知道,關鍵代碼1處獲取的factory是StreamUriLoader.Factory類型的,關鍵代碼2處就是調用了StreamUriLoader.Factory的build方法。
public class StreamUriLoader extends UriLoader<InputStream> implements StreamModelLoader<Uri> {
public static class Factory implements ModelLoaderFactory<Uri, InputStream> {
@Override
public ModelLoader<Uri, InputStream> build(Context context, GenericLoaderFactory factories) {
return new StreamUriLoader(context, factories.buildModelLoader(GlideUrl.class, InputStream.class));
}
@Override
public void teardown() {
// Do nothing.
}
}
...
}
這個方法內部返回的是一個StreamUriLoader類型的對象,到此,弄清楚了StreamStringLoader類的父類StringLoader的getResourceFetcher()方法中的uriLoader就是StreamUriLoader類型的對象。下面再次貼出
StringLoader的getResourceFetcher()方法,由於是重複貼出代碼,爲了減少文字篇幅,這裏省略了更多的代碼:
public class StringLoader<T> implements ModelLoader<String, T> {
...
@Override
public DataFetcher<T> getResourceFetcher(String model, int width, int height) {
...
// 關鍵代碼
return uriLoader.getResourceFetcher(uri, width, height);
}
...
}
通過前面分析知道這個方法中uriLoader是StreamUriLoader類型的,所以代碼就跳轉到了StreamUriLoader類的getResourceFetcher()方法中,StreamUriLoader類中沒有這個方法,是其父類UriLoader的方法
public abstract class UriLoader<T> implements ModelLoader<Uri, T> {
private final Context context;
private final ModelLoader<GlideUrl, T> urlLoader;
public UriLoader(Context context, ModelLoader<GlideUrl, T> urlLoader) {
this.context = context;
this.urlLoader = urlLoader;
}
@Override
public final DataFetcher<T> getResourceFetcher(Uri model, int width, int height) {
final String scheme = model.getScheme();
DataFetcher<T> result = null;
if (isLocalUri(scheme)) {
if (AssetUriParser.isAssetUri(model)) {
String path = AssetUriParser.toAssetPath(model);
result = getAssetPathFetcher(context, path);
} else {
result = getLocalUriFetcher(context, model);
}
} else if (urlLoader != null && ("http".equals(scheme) || "https".equals(scheme))) {
//關鍵代碼處
result = urlLoader.getResourceFetcher(new GlideUrl(model.toString()), width, height);
}
return result;
}
...
在這個方法內部,可以看到通過model.getScheme()方法來獲取scheme,平時開發時,從網絡獲取圖片時,傳入的url地址,一般都是http或者https開頭的,所以這個方法內部代碼的邏輯執行到關鍵代碼處,這裏又調用了urlLoader的getResourceFetcher方法,現在需要弄清楚,urlLoader是從哪裏來的,這個urlLoader是通過StreamUriLoader 的構造函數傳入並賦值的,經過前面的分析知道,StreamUriLoader的構造函數的調用是在
StreamUriLoader.Factory的build方法中。
public class StreamUriLoader extends UriLoader<InputStream> implements StreamModelLoader<Uri> {
public static class Factory implements ModelLoaderFactory<Uri, InputStream> {
@Override
public ModelLoader<Uri, InputStream> build(Context context, GenericLoaderFactory factories) {
return new StreamUriLoader(context, factories.buildModelLoader(GlideUrl.class, InputStream.class));
}
@Override
public void teardown() {
// Do nothing.
}
}
...
}
這個urlLoader的值就是通過factories.buildModelLoader(GlideUrl.class, InputStream.class)來賦值的,
factories.buildModelLoader(GlideUrl.class, InputStream.class)的分析過程,前面已經分析過了,這裏就進行簡單的分析,注意這裏傳入的是GlideUrl.class和InputStream.class,在分析前,在看看Glide的初始化,:
public class Glide {
...
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
...
//關鍵代碼處,這裏register()方法傳入的參數分別是GlideUrl.class,InputStream.class和new HttpUrlGlideUrlLoader.Factory對象
register(GlideUrl.class, InputStream.class, new HttpUrlGlideUrlLoader.Factory());
...
}
...
}
所以GenericLoaderFactory的buildModelLoader方法內部獲取的factory就是HttpUrlGlideUrlLoader.Factory,factory調動的build方法就是執行的HttpUrlGlideUrlLoader.Factory的build方法
public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
private final ModelCache<GlideUrl, GlideUrl> modelCache;
/**
* The default factory for {@link com.bumptech.glide.load.model.stream.HttpUrlGlideUrlLoader}s.
*/
public static class Factory implements ModelLoaderFactory<GlideUrl, InputStream> {
private final ModelCache<GlideUrl, GlideUrl> modelCache = new ModelCache<GlideUrl, GlideUrl>(500);
@Override
public ModelLoader<GlideUrl, InputStream> build(Context context, GenericLoaderFactory factories) {
return new HttpUrlGlideUrlLoader(modelCache);
}
@Override
public void teardown() {
// Do nothing.
}
}
...
從build方法中,可以知道,返回的是一個HttpUrlGlideUrlLoader類型的對象,到這裏弄清楚了StreamUriLoader類的getResourceFetcher()方法中
public abstract class UriLoader<T> implements ModelLoader<Uri, T> {
private final Context context;
private final ModelLoader<GlideUrl, T> urlLoader;
...
@Override
public final DataFetcher<T> getResourceFetcher(Uri model, int width, int height) {
final String scheme = model.getScheme();
DataFetcher<T> result = null;
if (isLocalUri(scheme)) {
...
} else if (urlLoader != null && ("http".equals(scheme) || "https".equals(scheme))) {
//關鍵代碼處
result = urlLoader.getResourceFetcher(new GlideUrl(model.toString()), width, height);
}
return result;
}
...
這個方法中的urlLoader的值就是HttpUrlGlideUrlLoader類型的對象。
urlLoader.getResourceFetcher(new GlideUrl(model.toString()), width, height)執行的就是HttpUrlGlideUrlLoader類的getResourceFetcher方法:
public class HttpUrlGlideUrlLoader implements ModelLoader<GlideUrl, InputStream> {
...
@Override
public DataFetcher<InputStream> getResourceFetcher(GlideUrl model, int width, int height) {
// GlideUrls memoize parsed URLs so caching them saves a few object instantiations and time spent parsing urls.
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
return new HttpUrlFetcher(url);
}
}
這個方法內部返回了一個HttpUrlFetcher類型的對象。到這裏纔剛剛分析完GenericRequest類的onSizeReady方法的關鍵代碼2處的dataFetcher 就是HttpUrlFetcher類型的對象。
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback, ResourceCallback {
@Override
public void onSizeReady(int width, int height) {
...
//關鍵代碼1,這裏的loadProvider其實就是FixedLoadProvider對象
ModelLoader<A, T> modelLoader = loadProvider.getModelLoader();
//關鍵代碼2
final DataFetcher<T> dataFetcher = modelLoader.getResourceFetcher(model, width, height);
if (dataFetcher == null) {
onException(new Exception("Failed to load model: \'" + model + "\'"));
return;
}
ResourceTranscoder<Z, R> transcoder = loadProvider.getTranscoder();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
loadedFromMemoryCache = true;
//關鍵代碼3
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
loadedFromMemoryCache = resource != null;
...
}
}
下面繼續分析GenericRequest類的onSizeReady方法的關鍵代碼3處的邏輯,這裏會調用Engine類的load方法,注意傳入的dataFetcher參數是HttpUrlFetcher類型的對象,傳入的loadProvider是FixedLoadProvider類型的對象。
public class Engine implements EngineJobListener,MemoryCache.ResourceRemovedListener,EngineResource.ResourceListener {
...
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
Util.assertMainThread();
long startTime = LogTime.getLogTime();
final String id = fetcher.getId();
EngineKey key = keyFactory.buildKey(id, signature, width, height, loadProvider.getCacheDecoder(),
loadProvider.getSourceDecoder(), transformation, loadProvider.getEncoder(),
transcoder, loadProvider.getSourceEncoder());
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
EngineJob current = jobs.get(key);
if (current != null) {
current.addCallback(cb);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//關鍵代碼1
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
//關鍵代碼2
DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
transcoder, diskCacheProvider, diskCacheStrategy, priority);
//關鍵代碼3
EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
//關鍵代碼4
engineJob.start(runnable);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
這個方法內部會在關鍵代碼1處創建一個EngineJob類型的對象,在關鍵代碼2處,創建一個DecodeJob類型的對象,注意傳入的構造函數的第4個參數是HttpUrlFetcher類型的對象,傳入的l第5個參數是FixedLoadProvider類型的對象 在關鍵代碼3處,創建一個EngineRunnable類型的對象,在關鍵代碼4處調用EngineJob類的start()方法,這樣
EngineRunnable的潤方法就會執行,下面看看EngineRunnable 的run方法的具體實現:
class EngineRunnable implements Runnable, Prioritized {
...
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
//關鍵代碼1
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
//關鍵代碼2
onLoadFailed(exception);
} else {
//關鍵代碼3
onLoadComplete(resource);
}
}
...
private Resource<?> decode() throws Exception {
if (isDecodingFromCache()) {
return decodeFromCache();
} else {
return decodeFromSource();
}
}
...
private Resource<?> decodeFromSource() throws Exception {
return decodeJob.decodeFromSource();
}
...
}
在EngineRunnable的run方法的關鍵代碼1處,會調用decode方法,在decode方法中,會如果已經緩存了,則走decodeFromCache()的邏輯,否則執行decodeFromSource()邏輯,下面以decodeFromSource()這個邏輯爲例來繼續下面的分析,decodeFromSource()邏輯這塊的邏輯,讀者可以自己去分析。
decodeFromSource()方法內部是調用了DecodeJob類的decodeFromSource()方法,下面看看這個方法
class DecodeJob<A, T, Z> {
...
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
...
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
//關鍵代碼1
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
//關鍵代碼2
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
...
}
在這個方法的關鍵代碼1處,調用了fetcher.loadData(priority),這裏的fetcher就是前面花了很大的篇幅分析得出的HttpUrlFetcher類型的對象。這樣代碼跳轉到了HttpUrlFetcher類的loadData方法中,注意方法的參數傳入的是一個priority,也就是,可以調整線程的優先級的,這表明Glide是可以設置線程的優先級的。下面看看HttpUrlFetcher類的loadData方法
public class HttpUrlFetcher implements DataFetcher<InputStream> {
...
private static final int MAXIMUM_REDIRECTS = 5;
...
@Override
public InputStream loadData(Priority priority) throws Exception {
return loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/, glideUrl.getHeaders());
}
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers)
throws IOException {
//如果重定向的次數超過5次,則拋出異常
if (redirects >= MAXIMUM_REDIRECTS) {
throw new IOException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new IOException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
//創建urlConnection對象,並進行網絡請求
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(2500);
urlConnection.setReadTimeout(2500);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
if (isCancelled) {
return null;
}
//獲取網絡請求的結果
final int statusCode = urlConnection.getResponseCode();
if (statusCode / 100 == 2) {
//statusCode是200.表示成功
return getStreamForSuccessfulRequest(urlConnection);
} else if (statusCode / 100 == 3) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new IOException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else {
if (statusCode == -1) {
throw new IOException("Unable to retrieve response code from HttpUrlConnection.");
}
throw new IOException("Request failed " + statusCode + ": " + urlConnection.getResponseMessage());
}
}
...
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
throws IOException {
if (TextUtils.isEmpty(urlConnection.getContentEncoding())) {
int contentLength = urlConnection.getContentLength();
stream = ContentLengthInputStream.obtain(urlConnection.getInputStream(), contentLength);
} else {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Got non empty content encoding: " + urlConnection.getContentEncoding());
}
stream = urlConnection.getInputStream();
}
return stream;
}
...
}
HttpUrlFetcher 類的loadData方法內部會調用到loadDataWithRedirects()方法,loadDataWithRedirects()內部會通過HttpURLConnection進行網絡請求,並調用getStreamForSuccessfulRequest()方法並獲取返回的InputStream。
到這裏才分析到Glide加載圖片的網絡請求。
回到DecodeJob類的decodeFromSource()方法,下面看看這個方法
class DecodeJob<A, T, Z> {
...
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
//關鍵代碼1
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
//關鍵代碼2
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
...
}
關鍵代碼1處,完成了網絡請求,並返回了InputStream,在關鍵代碼2處,處理流對象,將流對象解碼Bitmap或者Drawable類型的對象,這樣ImageView才能直接使用。關鍵代碼2處會調用decodeFromSourceData方法,
class DecodeJob<A, T, Z> {
...
private Resource<T> decodeFromSourceData(A data) throws IOException {
final Resource<T> decoded;
if (diskCacheStrategy.cacheSource()) {
//關鍵代碼,調用
decoded = cacheAndDecodeSourceData(data);
} else {
long startTime = LogTime.getLogTime();
decoded = loadProvider.getSourceDecoder().decode(data, width, height);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded from source", startTime);
}
}
return decoded;
}
...
}
由於Glide.with(this).load(url).into(iv);這個鏈式調用默認的DiskCacheStrategy.RESULT,這就導致
if (diskCacheStrategy.cacheSource()) 這個判斷條件不成立,會執行else分支的邏輯,下面以if分支的邏輯爲例來分析,代碼執行到關鍵代碼處cacheAndDecodeSourceData()方法,
class DecodeJob<A, T, Z> {
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException {
long startTime = LogTime.getLogTime();
//將InputStream轉換成 SourceWriter類型的對象
SourceWriter<A> writer = new SourceWriter<A>(loadProvider.getSourceEncoder(), data);
//將SourceWriter類型的對象寫入磁盤緩存,也就是緩存圖片到磁盤
diskCacheProvider.getDiskCache().put(resultKey.getOriginalKey(), writer);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Wrote source to cache", startTime);
}
startTime = LogTime.getLogTime();
//關鍵代碼
Resource<T> result = loadFromCache(resultKey.getOriginalKey());
if (Log.isLoggable(TAG, Log.VERBOSE) && result != null) {
logWithTimeAndKey("Decoded source from cache", startTime);
}
return result;
}
private Resource<T> loadFromCache(Key key) throws IOException {
File cacheFile = diskCacheProvider.getDiskCache().get(key);
if (cacheFile == null) {
return null;
}
Resource<T> result = null;
try {
//關鍵代碼
result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
} finally {
if (result == null) {
diskCacheProvider.getDiskCache().delete(key);
}
}
return result;
}
...
}
在DecodeJob類的cacheAndDecodeSourceData方法只,會將網絡請求的流數據轉換成 SourceWriter類型的對象的對象,並緩存到磁盤,接着調用loadFromCache()方法從緩存中獲取數據,這個方法內部,又調用了loadProvider.getCacheDecoder().decode(cacheFile, width, height)來返回結果。
這個loadProvider是什麼類型的呢?前面在創建DecodeJob對象時,就提過傳入的第4個參數是第HttpUrlFetcher類型的對象,傳入的l第5個參數是FixedLoadProvider類型的對象 ,所以,這裏的loadProvider其實就是FixedLoadProvider類型的對象。
所以代碼又跳轉到了FixedLoadProvider類的getCacheDecoder()方法:
@Override
public ResourceDecoder<File, Z> getCacheDecoder() {
return dataLoadProvider.getCacheDecoder();
}
這個方法內部又是通過dataLoadProvider.getCahcedDecoder()來返回的。前面繼續分析DrawableTypeRequest構造函數的關鍵代碼3處的代碼
...
private static <A, Z, R> FixedLoadProvider<A, ImageVideoWrapper, Z, R> buildProvider(Glide glide,
ModelLoader<A, InputStream> streamModelLoader,
ModelLoader<A, ParcelFileDescriptor> fileDescriptorModelLoader, Class<Z> resourceClass,
Class<R> transcodedClass,
ResourceTranscoder<Z, R> transcoder) {
...
//關鍵代碼3
return new FixedLoadProvider<A, ImageVideoWrapper, Z, R>(modelLoader, transcoder, dataLoadProvider);
...
}
在關鍵代碼3處創建了一個FixedLoadProvider對象,注意傳入的參數modelLoader就是ImageVideoModelLoader類型的對象,dataLoadProvider進過前面的分析可以知道就是ImageVideoGifDrawableLoadProvider類型的對象。可以知道FixedLoadProvider類的getCacheDecoder()方法內部的dataLoadProvider其實就是ImageVideoGifDrawableLoadProvider類型的對象。這樣代碼就跳轉到了ImageVideoGifDrawableLoadProvider類的getCacheDecoder()方法
public class ImageVideoGifDrawableLoadProvider implements DataLoadProvider<ImageVideoWrapper, GifBitmapWrapper> {
...
public ImageVideoGifDrawableLoadProvider(DataLoadProvider<ImageVideoWrapper, Bitmap> bitmapProvider,
DataLoadProvider<InputStream, GifDrawable> gifProvider, BitmapPool bitmapPool) {
//關鍵代碼3
final GifBitmapWrapperResourceDecoder decoder = new GifBitmapWrapperResourceDecoder(
//關鍵代碼4
bitmapProvider.getSourceDecoder(),
gifProvider.getSourceDecoder(),
bitmapPool
);
//關鍵代碼2
cacheDecoder = new FileToStreamDecoder<GifBitmapWrapper>(new GifBitmapWrapperStreamResourceDecoder(decoder));
sourceDecoder = decoder;
encoder = new GifBitmapWrapperResourceEncoder(bitmapProvider.getEncoder(), gifProvider.getEncoder());
//TODO: what about the gif provider?
sourceEncoder = bitmapProvider.getSourceEncoder();
}
@Override
public ResourceDecoder<File, GifBitmapWrapper> getCacheDecoder() {
//關鍵代碼1
return cacheDecoder;
}
...
}
這個方法的關鍵代碼1處內部返回的cacheDecoder是在關鍵代碼2處賦值的,返回了一個FileToStreamDecoder類型的對象。這個FileToStreamDecoder類型的對象內部又封裝了一個GifBitmapWrapperStreamResourceDecoder類型的對象,在關鍵代碼3處,這個GifBitmapWrapperStreamResourceDecoder內部有傳入了一個GifBitmapWrapperResourceDecoder類型的對象。在創建GifBitmapWrapperResourceDecoder 類型的對象時,在關鍵代碼4處,通過bitmapProvider.getSourceDecoder()創建了一個DataLoadProviderle類型的對象,這個bitmapProvider 又具體是什麼類型的對象呢?在解析繼續向下分析之前,在回頭看看Glide的初始化:
public class Glide {
Glide(Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, Context context, DecodeFormat decodeFormat) {
...
ImageVideoDataLoadProvider imageVideoDataLoadProvider =
new ImageVideoDataLoadProvider(streamBitmapLoadProvider, fileDescriptorLoadProvider);
...
dataLoadProviderRegistry.register(ImageVideoWrapper.class, GifBitmapWrapper.class,
new ImageVideoGifDrawableLoadProvider(imageVideoDataLoadProvider, gifDrawableLoadProvider, bitmapPool));
}
}
可以看到,Glide初始化時,對ImageVideoGifDrawableLoadProvider進行了初始化,並傳傳入了ImageVideoDataLoadProvider 類型的參數作爲ImageVideoGifDrawableLoadProvider的構造方法的第一個參數。所以,ImageVideoGifDrawableLoadProvider 的構造方法的關鍵代碼4處的bitmapProvider就是ImageVideoDataLoadProvider 類型的對象。這樣,
bitmapProvider.getSourceDecoder()的代碼執行邏輯就跳轉到了ImageVideoDataLoadProvider 類的getSourceDecoder()方法中
public class ImageVideoDataLoadProvider implements DataLoadProvider<ImageVideoWrapper, Bitmap> {
private final ImageVideoBitmapDecoder sourceDecoder;
private final ResourceDecoder<File, Bitmap> cacheDecoder;
private final ResourceEncoder<Bitmap> encoder;
private final ImageVideoWrapperEncoder sourceEncoder;
public ImageVideoDataLoadProvider(DataLoadProvider<InputStream, Bitmap> streamBitmapProvider,
DataLoadProvider<ParcelFileDescriptor, Bitmap> fileDescriptorBitmapProvider) {
encoder = streamBitmapProvider.getEncoder();
sourceEncoder = new ImageVideoWrapperEncoder(streamBitmapProvider.getSourceEncoder(),
fileDescriptorBitmapProvider.getSourceEncoder());
cacheDecoder = streamBitmapProvider.getCacheDecoder();
//關鍵代碼
sourceDecoder = new ImageVideoBitmapDecoder(streamBitmapProvider.getSourceDecoder(),
fileDescriptorBitmapProvider.getSourceDecoder());
}
...
@Override
public ResourceDecoder<ImageVideoWrapper, Bitmap> getSourceDecoder() {
return sourceDecoder;
}
...
}
這個方法內部返回的是一個ImageVideoBitmapDecoder類型的對象,不過這個對象在創建時,又調用了streamBitmapProvider.getSourceDecoder(),這個streamBitmapProvider也在Glide類初始化時,傳入的,這裏就不再帶着大家看Glide初始化的源碼了,這裏的streamBitmapProvider就是StreamBitmapDataLoadProvider類型的,所以代碼又跳轉到了StreamBitmapDataLoadProvider的getSourceDecoder()方法
public class StreamBitmapDataLoadProvider implements DataLoadProvider<InputStream, Bitmap> {
private final StreamBitmapDecoder decoder;
private final BitmapEncoder encoder;
private final StreamEncoder sourceEncoder;
private final FileToStreamDecoder<Bitmap> cacheDecoder;
public StreamBitmapDataLoadProvider(BitmapPool bitmapPool, DecodeFormat decodeFormat) {
sourceEncoder = new StreamEncoder();
//關鍵代碼
decoder = new StreamBitmapDecoder(bitmapPool, decodeFormat);
encoder = new BitmapEncoder();
cacheDecoder = new FileToStreamDecoder<Bitmap>(decoder);
}
...
@Override
public ResourceDecoder<InputStream, Bitmap> getSourceDecoder() {
return decoder;
}
...
}
StreamBitmapDataLoadProvider的getSourceDecoder()方法內部最後返回的是一個StreamBitmapDecoder類型的對象,這個後面會用到。到這裏可以認爲ImageVideoGifDrawableLoadProvider類的getCacheDecoder()方法返回的就是一個StreamBitmapDecoder類型的對象。注意只能認爲,實際卻不是,實際上返回的是FileToStreamDecoder類型的對象。這裏這樣表述是爲了後面分析時,方便理解。
回到DecodeJob類的loadFromCache方法,
class DecodeJob<A, T, Z> {
...
private Resource<T> loadFromCache(Key key) throws IOException {
File cacheFile = diskCacheProvider.getDiskCache().get(key);
if (cacheFile == null) {
return null;
}
Resource<T> result = null;
try {
//關鍵代碼
result = loadProvider.getCacheDecoder().decode(cacheFile, width, height);
} finally {
if (result == null) {
diskCacheProvider.getDiskCache().delete(key);
}
}
return result;
}
...
}
關鍵代碼處 loadProvider.getCacheDecoder()獲取的其實就是一個FileToStreamDecoder類型的對象。但是經過前面的分析,FileStreamDecoder內部封裝了多層的Decoder,並調用了這個對象的decode方法,經過內部封裝的各個Decoder,會最終調用到StreamBitmapDecoder類的decode方法,所以,這也是爲什麼上面說 loadProvider.getCacheDecoder()獲取的對象可以認爲是StreamBitmapDecoder類型的對象。
public class StreamBitmapDecoder implements ResourceDecoder<InputStream, Bitmap> {
...
@Override
public Resource<Bitmap> decode(InputStream source, int width, int height) {
Bitmap bitmap = downsampler.decode(source, bitmapPool, width, height, decodeFormat);
return BitmapResource.obtain(bitmap, bitmapPool);
}
...
}
這個方法戶返回一個Bitmap對象,這樣就將InputStream流數據解碼成Bitmap類型的對象了。
這樣DecodeJob類的decodeFromSource()方法得到的就是一個Resource類型的對象。下面再次貼出DecodeJob類的decodeFromSource()方法
class DecodeJob<A, T, Z> {
...
public Resource<Z> decodeFromSource() throws Exception {
Resource<T> decoded = decodeSource();
return transformEncodeAndTranscode(decoded);
}
...
private Resource<T> decodeSource() throws Exception {
Resource<T> decoded = null;
try {
long startTime = LogTime.getLogTime();
//關鍵代碼1
final A data = fetcher.loadData(priority);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Fetched data", startTime);
}
if (isCancelled) {
return null;
}
//關鍵代碼2
decoded = decodeFromSourceData(data);
} finally {
fetcher.cleanup();
}
return decoded;
}
...
}
經過層層向上返回,返回到EngineRunnable 的run方法的具體實現:
class EngineRunnable implements Runnable, Prioritized {
...
@Override
public void run() {
if (isCancelled) {
return;
}
Exception exception = null;
Resource<?> resource = null;
try {
//關鍵代碼1
resource = decode();
} catch (Exception e) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Exception decoding", e);
}
exception = e;
}
if (isCancelled) {
if (resource != null) {
resource.recycle();
}
return;
}
if (resource == null) {
//關鍵代碼2
onLoadFailed(exception);
} else {
//關鍵代碼3
onLoadComplete(resource);
}
}
...
}
在關鍵代碼1處,這個resource 就是Resource類型的。下面繼續分析這個方法,如果recource爲null,則執行關鍵代碼2處邏輯,否則執行關鍵代碼3處的邏輯,下面先分析關鍵代碼2處的邏輯,
class EngineRunnable implements Runnable, Prioritized {
...
private void onLoadFailed(Exception e) {
if (isDecodingFromCache()) {
//關鍵代碼1
stage = Stage.SOURCE;
manager.submitForSource(this);
} else {
manager.onException(e);
}
}
...
}
這個方法內部不管是執行if邏輯還是else邏輯,最終都會調用 manager.onException(e),這裏的 manager其實就是EngineJob類型的對象。這樣代碼執行到EngineJob類的onException()方法
class EngineJob implements EngineRunnable.EngineRunnableManager {
...
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
@Override
public void onException(final Exception e) {
this.exception = e;
MAIN_THREAD_HANDLER.obtainMessage(MSG_EXCEPTION, this).sendToTarget();
}
...
private void handleExceptionOnMainThread() {
if (isCancelled) {
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received an exception without any callbacks to notify");
}
hasException = true;
listener.onEngineJobComplete(key, null);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
//關鍵代碼
cb.onException(exception);
}
}
}
private static class MainThreadCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message message) {
if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
EngineJob job = (EngineJob) message.obj;
if (MSG_COMPLETE == message.what) {
job.handleResultOnMainThread();
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
}
這個方法內部通過MAIN_THREAD_HANDLER這個handler發送下消息,將代碼的執行線程從子線程切換到UI線程。並最終執行到handleExceptionOnMainThread()方法中,在這個方法中的會遍歷cbs,並調用其每個元素的onException方法,那這個cbs是什麼,cbs其實就是一個ArrayList,它裏面存放的是ResourceCallback類型的對象 ,那cbs這個集合是在什麼時候存入這些ResourceCallback類型的對象的呢?是在Engine的load方法中傳入的
public class Engine implements EngineJobListener,MemoryCache.ResourceRemovedListener,EngineResource.ResourceListener {
...
public <T, Z, R> LoadStatus load(Key signature, int width, int height, DataFetcher<T> fetcher,
DataLoadProvider<T, Z> loadProvider, Transformation<Z> transformation, ResourceTranscoder<Z, R> transcoder,
Priority priority, boolean isMemoryCacheable, DiskCacheStrategy diskCacheStrategy, ResourceCallback cb) {
...
EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
...
engineJob.addCallback(cb);
...
return new LoadStatus(cb, engineJob);
}
那這個Engine的 load方法是在何處調用的呢?
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,ResourceCallback {
@Override
public void onSizeReady(int width, int height) {
...
//注意,調用Engine的load方法,傳入的最後一個參數是this,也就是GenericRequest類本身,GenericRequest也實現了ResourceCallback 接口
loadStatus = engine.load(signature, width, height, dataFetcher, loadProvider, transformation, transcoder,
priority, isMemoryCacheable, diskCacheStrategy, this);
...
}
...
}
所以,EngineJob類的 handleExceptionOnMainThread()方法內部遍歷cbs這個集合的內部存放的都是GenericRequest類型的對象,那麼調用的就是GenericRequest類的onException()方法,
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,ResourceCallback {
...
@Override
public void onException(Exception e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "load failed", e);
}
status = Status.FAILED;
//TODO: what if this is a thumbnail request?
if (requestListener == null || !requestListener.onException(e, model, target, isFirstReadyResource())) {
setErrorPlaceholder(e);
}
}
...
private void setErrorPlaceholder(Exception e) {
if (!canNotifyStatusChanged()) {
return;
}
Drawable error = model == null ? getFallbackDrawable() : null;
if (error == null) {
error = getErrorDrawable();
}
if (error == null) {
error = getPlaceholderDrawable();
}
target.onLoadFailed(e, error);
}
}
這個方法內部最終會執行到 target.onLoadFailed(e, error);這樣代碼,這裏的target就是前面分析glide.buildImageViewTarget(view, transcodeClass)創建的對象GlideDrawableImageViewTarget類型的對象,這樣代碼又執行到了GlideDrawableImageViewTarget類的onLoadFailed()方法,這個方式是GlideDrawableImageViewTarget類的父類ImageViewTarget的的方法
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements GlideAnimation.ViewAdapter {
...
@Override
public void onLoadFailed(Exception e, Drawable errorDrawable) {
view.setImageDrawable(errorDrawable);
}
...
}
這個方法中,最終將結果設置到了ImageView上面。到這裏分析完了EngineRunnable 的run方法的關鍵代碼2處的邏輯, 下面繼續分析關鍵代碼3處的邏輯,具體實現:
class EngineRunnable implements Runnable, Prioritized {
...
@Override
public void run() {
...
if (resource == null) {
//關鍵代碼2
onLoadFailed(exception);
} else {
//關鍵代碼3
onLoadComplete(resource);
}
}
...
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
...
}
在關鍵代碼3處,回調用onLoadComplete()方法,這個onLoadComplete()方法內部又調用了EngineJob類的onResourceReady()方法
class EngineJob implements EngineRunnable.EngineRunnableManager {
...
private static final Handler MAIN_THREAD_HANDLER = new Handler(Looper.getMainLooper(), new MainThreadCallback());
...
@Override
public void onResourceReady(final Resource<?> resource) {
this.resource = resource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
// synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
}
private void handleResultOnMainThread() {
if (isCancelled) {
resource.recycle();
return;
} else if (cbs.isEmpty()) {
throw new IllegalStateException("Received a resource without any callbacks to notify");
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
// Hold on to resource for duration of request so we don't recycle it in the middle of notifying if it
// synchronously released by one of the callbacks.
engineResource.acquire();
listener.onEngineJobComplete(key, engineResource);
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
//關鍵代碼
cb.onResourceReady(engineResource);
}
}
// Our request is complete, so we can release the resource.
engineResource.release();
}
...
private static class MainThreadCallback implements Handler.Callback {
@Override
public boolean handleMessage(Message message) {
if (MSG_COMPLETE == message.what || MSG_EXCEPTION == message.what) {
EngineJob job = (EngineJob) message.obj;
if (MSG_COMPLETE == message.what) {
job.handleResultOnMainThread();
} else {
job.handleExceptionOnMainThread();
}
return true;
}
return false;
}
}
}
這個方法內部會通過handler從子線程切換到UI線程,並最終執行到handleResultOnMainThread() 方法,在handleResultOnMainThread() 方法內部也是遍歷cbs這個ArrayList集合,並調用集合中的元素的onResourceReady()方法,前面分析失敗時,就知道cbs集合中的 元素就是
GenericRequest類型的對象.所以代碼執行到GenericRequest類的onResourceReady()方法
public final class GenericRequest<A, T, Z, R> implements Request, SizeReadyCallback,ResourceCallback {
...
@Override
public void onResourceReady(Resource<?> resource) {
if (resource == null) {
onException(new Exception("Expected to receive a Resource<R> with an object of " + transcodeClass
+ " inside, but instead got null."));
return;
}
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
onException(new Exception("Expected to receive an object of " + transcodeClass
+ " but instead got " + (received != null ? received.getClass() : "") + "{" + received + "}"
+ " inside Resource{" + resource + "}."
+ (received != null ? "" : " "
+ "To indicate failure return a null Resource object, "
+ "rather than a Resource object containing null data.")
));
return;
}
if (!canSetResource()) {
releaseResource(resource);
// We can't set the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
onResourceReady(resource, (R) received);
}
/**
* Internal {@link #onResourceReady(Resource)} where arguments are known to be safe.
*
* @param resource original {@link Resource}, never <code>null</code>
* @param result object returned by {@link Resource#get()}, checked for type and never <code>null</code>
*/
private void onResourceReady(Resource<?> resource, R result) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstResource)) {
GlideAnimation<R> animation = animationFactory.build(loadedFromMemoryCache, isFirstResource);
//關鍵代碼
target.onResourceReady(result, animation);
}
notifyLoadSuccess();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logV("Resource ready in " + LogTime.getElapsedMillis(startTime) + " size: "
+ (resource.getSize() * TO_MEGABYTE) + " fromCache: " + loadedFromMemoryCache);
}
}
...
}
GenericRequest類的onResourceReady()方法內部調用其重載方法,並在這個重載方法內部最終執行
target.onResourceReady(result, animation);
這行代碼,前面已經分析過,這個target就是GlideDrawableImageViewTarget類型的對象,所以代碼執行到GlideDrawableImageViewTarget類的onResourceReady()方法
public class GlideDrawableImageViewTarget extends ImageViewTarget<GlideDrawable> {
@Override
public void onResourceReady(GlideDrawable resource, GlideAnimation<? super GlideDrawable> animation) {
if (!resource.isAnimated()) {
float viewRatio = view.getWidth() / (float) view.getHeight();
float drawableRatio = resource.getIntrinsicWidth() / (float) resource.getIntrinsicHeight();
if (Math.abs(viewRatio - 1f) <= SQUARE_RATIO_MARGIN
&& Math.abs(drawableRatio - 1f) <= SQUARE_RATIO_MARGIN) {
resource = new SquaringDrawable(resource, view.getWidth());
}
}
//關鍵代碼
super.onResourceReady(resource, animation);
this.resource = resource;
resource.setLoopCount(maxLoopCount);
resource.start();
}
...
}
這個方法內部,在關鍵代碼處,調用其父類的ImageViewTarget的onResourceReady()方法
@Override
public void onResourceReady(Z resource, GlideAnimation<? super Z> glideAnimation) {
if (glideAnimation == null || !glideAnimation.animate(resource, this)) {
setResource(resource);
}
}
這個方法內部又調用惡劣子類的setResource()方法
public class GlideDrawableImageViewTarget extends ImageViewTarget<GlideDrawable>
...
@Override
protected void setResource(GlideDrawable resource) {
view.setImageDrawable(resource);
}
...
}
最終還是調用了在into方法中傳入的imageview的setImageDrawable方法,將圖片設置到了ImageView上面顯示出來。
到這裏,終於將Glide.with(this).load(url).into(iv);這樣代碼的調用過程分析完畢,只是分析了部分邏輯,如果圖片已經緩存的邏輯,還未分析,加gif動圖的 過程也未分析,讀者有興趣,可以自己去分析,分析過程中,筆者也是有幾次差點被源碼繞暈了,不過還好最終還是堅持分析完了,在分析過程中,主要是很多成員變量都是接口類型的,需要找到這些成員變量的具體類型,才能繼續向下分析,但是這些成員變量的賦值很多是在Glide的初始化的時候賦值的,往往爲了找到一個變量的賦值,一步一步的跟進,最後跟進到了Glided的初始化過程,後面在回過頭繼續分析時,要想很久,是從哪裏開始繼續分析,建議讀者在分析時,結合使用StartUML這個工具,效果可能好點。