隨著Android開發(fā)的愈漸火熱,各種Android的圖片加載庫也曾出不窮,比較有名的有:Fresco、Picasso、Universal Image Loader等等。在這篇文章中,我會通過源碼來簡單地分析一下Glide使用時所發(fā)生的事情。
使用方法
對于Glide的使用方法不是本文的重點,在這里就不多說了,這里貼出Glide的Github地址,如果對使用方法有什么疑問的就上官方去看看吧。這里我們從Glide最簡單的三行使用方法入手進行分析:
Glide.with(...)
.load(...)
.into(...);
流程分析
首先我們進入Glide類看看with()方法:
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
我們可以看到with()方法是Glide類中的一個靜態(tài)方法,它會創(chuàng)建一個RequestManagerRetriever對象,在這里我們先不看這個類在創(chuàng)建過程中發(fā)生的事情,先看看它通過傳入的Context對象所返回的這個RequestManager對象。
對于RequestManager這個類,官方文檔是這樣描述的:
A class for managing and starting requests for Glide. Can use activity, fragment and connectivity lifecycle events to intelligently stop, start, and restart requests. Retrieve either by instantiating a new object, or to take advantage built in Activity and Fragment lifecycle handling, use the static Glide.load methods with your Fragment or Activity.
本人英文一般,就不逐字逐句地翻譯了??傊瑢τ?strong>RequestManager這個類的定位就是對圖片加載請求進行管理的類,并且它會根據(jù)與其產生聯(lián)系的Context對象的生命周期來管理圖片加載的過程。因此,圖片資源加載進ImageView的過程事實上是由它來一手掌管的。
知道了這些,我們接下來來看看它的load()方法,也就是我們將資源路徑傳入的這個方法,這里我們以傳入一個Uri為例:
public DrawableTypeRequest<Uri> load(Uri uri) {
return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
在這個方法中使用了DrawableTypeRequest中的load()方法去加載這個uri:
public DrawableRequestBuilder<ModelType> load(ModelType model) {
super.load(model);
return this;
}
這個方法的泛型參數(shù)ModelType在這里所對應的實際類型就是我們傳入的資源類型Uri,并且調用了DrawableRequestBuilder的父類方法load()來處理。
GenericRequestBuilder就是DrawableRequestBuilder的父類,這個類及其子類的作用就是用于請求加載的。我們來看看里面剛剛提到的load()方法:
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
這里我們發(fā)現(xiàn),load()方法僅僅是將資源——這里就是我們的圖片資源Uri賦值給了一個變量model,至于圖片資源究竟是怎么加載進ImageView的,我們回到這里實際進行加載請求的類DrawableRequestBuilder去看看它當中被我們最后調用的into()方法:
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
和load()方法相同,這里也調用了父類GenericRequestBuilder的into()方法:
public Target<TranscodeType> into(ImageView view) {
......
return into(glide.buildImageViewTarget(view, transcodeClass));
}
對于這個方法我們只看最后一句代碼。在這里又再次回到一開始的Glide,并調用了其中的buildImageViewTarget()方法,而在這個方法中傳入了一個GlideDrawable對象transcodedClass:
<R> Target<R> buildImageViewTarget(ImageView imageView, Class<R> transcodedClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodedClass);
}
我們繼續(xù)跟蹤下去:
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)");
}
}
經過反復地輾轉我們終于發(fā)現(xiàn)了上面我們傳入into()方法中的是一個和我們所要將圖片加載進的ImageView相關的GlideDrawableImageViewTarget對象。我們先記住這一點,不繼續(xù)深究下去,先回頭看看那個GenericRequestBuilder中的into()方法:
public <Y extends Target<TranscodeType>> Y into(Y target) {
......
Request request = buildRequest(target);
target.setRequest(request);
......
requestTracker.runRequest(request);
return target;
}
這段代碼所做的事情根據(jù)方法名很容易就能猜到,它先根據(jù)傳入的一個Target對象創(chuàng)建一個Request,并將兩者建立關聯(lián),最后執(zhí)行加載請求。
這里我們反過來會發(fā)現(xiàn),這個Target的實際對象就是我們剛剛所說的那個GlideDrawable,另外談到請求,是不是想到我們前面load()進去的那個Uri對象了呢?一陣云里霧里,整個內容終于聯(lián)系了起來,那么我們就先來看看這個Request對象究竟是怎么創(chuàng)建的:
private Request buildRequest(Target<TranscodeType> target) {
......
return buildRequestRecursive(target, null);
}
這里又將那個Target對象傳進一個buildRequestRecursive()方法中:
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
......
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
對于這個方法,我們重點來關注一下其中的一行代碼,其中涉及了obtainRequest()方法,這個方法有四個參數(shù),其中最重要的就是第一個,這里將剛剛的Target對象給傳了進去,我們接下來看一下這個方法:
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);
}
這個方法中只做了一件事,調用了GenericRequest類的靜態(tài)方法obtain(),并且傳入了很多的參數(shù),這里注意其中的參數(shù)target,即上面的GlideDrawableImageViewTarget對象,另外還有就是這里執(zhí)行了Glide中的getEngine()方法,還有資源模型model。然后繼續(xù)往下看:
public static <A, T, Z, R> GenericRequest<A, T, Z, R> obtain(
LoadProvider<A, T, Z, R> loadProvider,
A model,
Key signature,
Context context,
Priority priority,
Target<R> target,
float sizeMultiplier,
Drawable placeholderDrawable,
int placeholderResourceId,
Drawable errorDrawable,
int errorResourceId,
Drawable fallbackDrawable,
int fallbackResourceId,
RequestListener<? super A, R> requestListener,
RequestCoordinator requestCoordinator,
Engine engine,
Transformation<Z> transformation,
Class<R> transcodeClass,
boolean isMemoryCacheable,
GlideAnimationFactory<R> animationFactory,
int overrideWidth,
int overrideHeight,
DiskCacheStrategy diskCacheStrategy) {
@SuppressWarnings("unchecked")
GenericRequest<A, T, Z, R> request = (GenericRequest<A, T, Z, R>) REQUEST_POOL.poll();
if (request == null) {
request = new GenericRequest<A, T, Z, R>();
}
request.init(loadProvider,
model,
signature,
context,
priority,
target,
sizeMultiplier,
placeholderDrawable,
placeholderResourceId,
errorDrawable,
errorResourceId,
fallbackDrawable,
fallbackResourceId,
requestListener,
requestCoordinator,
engine,
transformation,
transcodeClass,
isMemoryCacheable,
animationFactory,
overrideWidth,
overrideHeight,
diskCacheStrategy);
return request;
}
這一段看上去有點長,但是其實也只涉及到了一個方法init(),這個方法同樣接受了很多參數(shù),并且在這個方法中,做的也只有一件事,就是將這些傳入的參數(shù)一一賦值給GenericRequest的成員變量:
private void init(
LoadProvider<A, T, Z, R> loadProvider,
A model,
Key signature,
Context context,
Priority priority,
Target<R> target,
float sizeMultiplier,
Drawable placeholderDrawable,
int placeholderResourceId,
Drawable errorDrawable,
int errorResourceId,
Drawable fallbackDrawable,
int fallbackResourceId,
RequestListener<? super A, R> requestListener,
RequestCoordinator requestCoordinator,
Engine engine,
Transformation<Z> transformation,
Class<R> transcodeClass,
boolean isMemoryCacheable,
GlideAnimationFactory<R> animationFactory,
int overrideWidth,
int overrideHeight,
DiskCacheStrategy diskCacheStrategy) {
this.loadProvider = loadProvider;
this.model = model;
this.signature = signature;
this.fallbackDrawable = fallbackDrawable;
this.fallbackResourceId = fallbackResourceId;
this.context = context.getApplicationContext();
this.priority = priority;
this.target = target;
this.sizeMultiplier = sizeMultiplier;
this.placeholderDrawable = placeholderDrawable;
this.placeholderResourceId = placeholderResourceId;
this.errorDrawable = errorDrawable;
this.errorResourceId = errorResourceId;
this.requestListener = requestListener;
this.requestCoordinator = requestCoordinator;
this.engine = engine;
this.transformation = transformation;
this.transcodeClass = transcodeClass;
this.isMemoryCacheable = isMemoryCacheable;
this.animationFactory = animationFactory;
this.overrideWidth = overrideWidth;
this.overrideHeight = overrideHeight;
this.diskCacheStrategy = diskCacheStrategy;
status = Status.PENDING;
......
}
到這里對于加載請求的設置幾本完成,我們再回去看看那句運行加載的代碼requestTracker.runRequest(request);所做的具體的事情:
public void runRequest(Request request) {
......
if (!isPaused) {
request.begin();
} else {
......
}
}
這里調用了剛剛設置好的Request對象的begin()方法,而這里的Request對象的實際類型就是上面我們所看到的GenericRequest對象。于是,我們來看看它的begin()方法:
public void begin() {
......
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
......
}
這里我們需要關注的就是一個Target對象的onLoadStarted()方法,在這里我們記起這個Target對象的實際類型就是上面的init()方法中所設置的GlideDrawableImageViewTarget對象。也許你會認為這個begin()方法就是資源加載進ImageView的關鍵,但是當我們點進去查看它的begin()方法時卻發(fā)現(xiàn)并不如我們所想,它只是為我們的ImageView設置了一個占位圖,并沒有做其他的事情。但是我們在查看GlideDrawableImageViewTarget的源碼的時候,我們發(fā)現(xiàn)了這么一個方法onResourceReady(),在這個方法中有這么一句代碼:
setResource(resource);
接著看看setResource():
public void setResource(GlideDrawable resource) {
view.setImageDrawable(resource);
}
這里的resource我們猜應該就是圖片資源了,也會是說這里所做的事情就是最后將圖片呈現(xiàn)在ImageView上,但程序究竟是怎么到這里的呢,我們想到了上面的getEngine()方法,于是我們來看看這里所做的事情:
Engine getEngine() {
return engine;
}
這個Engine又是一個非常重要的類,我們來看看這個類的官方介紹:
Responsible for starting loads and managing active and cached resources.
我們發(fā)現(xiàn)這個類就是真正用來管理加載的類。但是這個不是我這篇文章的重點,關于它所作的事情我會在后面的文章中對它進行簡析。既然這個Engine對象是用來加載資源的,那么我們就想到了一開始的那個上面另外一個要記住的model,看看它們是怎么運用的。要想知道這到底是怎么使用的,我在這里貼出最重要的一段:
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
這個方法是EngineRunnable類中的,這個類從名字就可以看出來它的作用就是響應Engine的。而這里的onResourceReady()則是觸發(fā)了GenericRequest中的一個回調onResourceReady():
public void onResourceReady(Resource<?> resource) {
......
onResourceReady(resource, (R) received);
}
這里又調用了該類中的一個重載方法:
private void onResourceReady(Resource<?> resource, R result) {
......
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstResource)) {
......
}
notifyLoadSuccess();
......
}
這里我們看到了,這個方法使用到了model,而這個方法則屬于一個RequestListener回調接口,這個回調接口究竟會在哪里被調用呢,其實就是我們上面提到的GlideDrawableImageViewTarget的onResourceReady(),而在這個方法中,另一個參數(shù)target在這里的實際類型就是GlideDrawableImageViewTarget。到這里我們終于是弄明白整個圖片資源的加載過程了。
這里用了大量的篇幅大致地給大家介紹了一下Glide的大致加載流程,但是在這其中我們還有很多關于圖片加載的所必需弄懂的細節(jié)并沒有進行介紹,但是這篇文章就先到這里,關于這些東西我會在后續(xù)的文章中盡我所能地分析給大家。