隨著Android開發(fā)的愈漸火熱苍匆,各種Android的圖片加載庫(kù)也曾出不窮系冗,比較有名的有:Fresco淹仑、Picasso、Universal Image Loader等等令杈。在這篇文章中走敌,我會(huì)通過(guò)源碼來(lái)簡(jiǎn)單地分析一下Glide使用時(shí)所發(fā)生的事情。
使用方法
對(duì)于Glide的使用方法不是本文的重點(diǎn)这揣,在這里就不多說(shuō)了悔常,這里貼出Glide的Github地址,如果對(duì)使用方法有什么疑問(wèn)的就上官方去看看吧给赞。這里我們從Glide最簡(jiǎn)單的三行使用方法入手進(jìn)行分析:
Glide.with(...)
.load(...)
.into(...);
流程分析
首先我們進(jìn)入Glide類看看with()方法:
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
我們可以看到with()方法是Glide類中的一個(gè)靜態(tài)方法机打,它會(huì)創(chuàng)建一個(gè)RequestManagerRetriever對(duì)象,在這里我們先不看這個(gè)類在創(chuàng)建過(guò)程中發(fā)生的事情片迅,先看看它通過(guò)傳入的Context對(duì)象所返回的這個(gè)RequestManager對(duì)象残邀。
對(duì)于RequestManager這個(gè)類,官方文檔是這樣描述的:
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.
本人英文一般柑蛇,就不逐字逐句地翻譯了芥挣。總之耻台,對(duì)于RequestManager這個(gè)類的定位就是對(duì)圖片加載請(qǐng)求進(jìn)行管理的類空免,并且它會(huì)根據(jù)與其產(chǎn)生聯(lián)系的Context對(duì)象的生命周期來(lái)管理圖片加載的過(guò)程。因此盆耽,圖片資源加載進(jìn)ImageView的過(guò)程事實(shí)上是由它來(lái)一手掌管的蹋砚。
知道了這些扼菠,我們接下來(lái)來(lái)看看它的load()方法,也就是我們將資源路徑傳入的這個(gè)方法坝咐,這里我們以傳入一個(gè)Uri為例:
public DrawableTypeRequest<Uri> load(Uri uri) {
return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
在這個(gè)方法中使用了DrawableTypeRequest中的load()方法去加載這個(gè)uri:
public DrawableRequestBuilder<ModelType> load(ModelType model) {
super.load(model);
return this;
}
這個(gè)方法的泛型參數(shù)ModelType在這里所對(duì)應(yīng)的實(shí)際類型就是我們傳入的資源類型Uri循榆,并且調(diào)用了DrawableRequestBuilder的父類方法load()來(lái)處理。
GenericRequestBuilder就是DrawableRequestBuilder的父類墨坚,這個(gè)類及其子類的作用就是用于請(qǐng)求加載的秧饮。我們來(lái)看看里面剛剛提到的load()方法:
public GenericRequestBuilder<ModelType, DataType, ResourceType, TranscodeType> load(ModelType model) {
this.model = model;
isModelSet = true;
return this;
}
這里我們發(fā)現(xiàn),load()方法僅僅是將資源——這里就是我們的圖片資源Uri賦值給了一個(gè)變量model泽篮,至于圖片資源究竟是怎么加載進(jìn)ImageView的盗尸,我們回到這里實(shí)際進(jìn)行加載請(qǐng)求的類DrawableRequestBuilder去看看它當(dāng)中被我們最后調(diào)用的into()方法:
public Target<GlideDrawable> into(ImageView view) {
return super.into(view);
}
和load()方法相同,這里也調(diào)用了父類GenericRequestBuilder的into()方法:
public Target<TranscodeType> into(ImageView view) {
......
return into(glide.buildImageViewTarget(view, transcodeClass));
}
對(duì)于這個(gè)方法我們只看最后一句代碼帽撑。在這里又再次回到一開始的Glide振劳,并調(diào)用了其中的buildImageViewTarget()方法,而在這個(gè)方法中傳入了一個(gè)GlideDrawable對(duì)象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)");
}
}
經(jīng)過(guò)反復(fù)地輾轉(zhuǎn)我們終于發(fā)現(xiàn)了上面我們傳入into()方法中的是一個(gè)和我們所要將圖片加載進(jìn)的ImageView相關(guān)的GlideDrawableImageViewTarget對(duì)象油狂。我們先記住這一點(diǎn),不繼續(xù)深究下去寸癌,先回頭看看那個(gè)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ù)傳入的一個(gè)Target對(duì)象創(chuàng)建一個(gè)Request,并將兩者建立關(guān)聯(lián)蒸苇,最后執(zhí)行加載請(qǐng)求磷蛹。
這里我們反過(guò)來(lái)會(huì)發(fā)現(xiàn),這個(gè)Target的實(shí)際對(duì)象就是我們剛剛所說(shuō)的那個(gè)GlideDrawable溪烤,另外談到請(qǐng)求味咳,是不是想到我們前面load()進(jìn)去的那個(gè)Uri對(duì)象了呢?一陣云里霧里檬嘀,整個(gè)內(nèi)容終于聯(lián)系了起來(lái)槽驶,那么我們就先來(lái)看看這個(gè)Request對(duì)象究竟是怎么創(chuàng)建的:
private Request buildRequest(Target<TranscodeType> target) {
......
return buildRequestRecursive(target, null);
}
這里又將那個(gè)Target對(duì)象傳進(jìn)一個(gè)buildRequestRecursive()方法中:
private Request buildRequestRecursive(Target<TranscodeType> target, ThumbnailRequestCoordinator parentCoordinator) {
......
return obtainRequest(target, sizeMultiplier, priority, parentCoordinator);
}
對(duì)于這個(gè)方法,我們重點(diǎn)來(lái)關(guān)注一下其中的一行代碼鸳兽,其中涉及了obtainRequest()方法掂铐,這個(gè)方法有四個(gè)參數(shù),其中最重要的就是第一個(gè)揍异,這里將剛剛的Target對(duì)象給傳了進(jìn)去全陨,我們接下來(lái)看一下這個(gè)方法:
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);
}
這個(gè)方法中只做了一件事,調(diào)用了GenericRequest類的靜態(tài)方法obtain()衷掷,并且傳入了很多的參數(shù)辱姨,這里注意其中的參數(shù)target,即上面的GlideDrawableImageViewTarget對(duì)象戚嗅,另外還有就是這里執(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;
}
這一段看上去有點(diǎn)長(zhǎng),但是其實(shí)也只涉及到了一個(gè)方法init()镜悉,這個(gè)方法同樣接受了很多參數(shù)祟辟,并且在這個(gè)方法中,做的也只有一件事侣肄,就是將這些傳入的參數(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;
......
}
到這里對(duì)于加載請(qǐng)求的設(shè)置幾本完成旧困,我們?cè)倩厝タ纯茨蔷溥\(yùn)行加載的代碼requestTracker.runRequest(request);所做的具體的事情:
public void runRequest(Request request) {
......
if (!isPaused) {
request.begin();
} else {
......
}
}
這里調(diào)用了剛剛設(shè)置好的Request對(duì)象的begin()方法,而這里的Request對(duì)象的實(shí)際類型就是上面我們所看到的GenericRequest對(duì)象稼锅。于是吼具,我們來(lái)看看它的begin()方法:
public void begin() {
......
if (!isComplete() && !isFailed() && canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
......
}
這里我們需要關(guān)注的就是一個(gè)Target對(duì)象的onLoadStarted()方法,在這里我們記起這個(gè)Target對(duì)象的實(shí)際類型就是上面的init()方法中所設(shè)置的GlideDrawableImageViewTarget對(duì)象矩距。也許你會(huì)認(rèn)為這個(gè)begin()方法就是資源加載進(jìn)ImageView的關(guān)鍵拗盒,但是當(dāng)我們點(diǎn)進(jìn)去查看它的begin()方法時(shí)卻發(fā)現(xiàn)并不如我們所想,它只是為我們的ImageView設(shè)置了一個(gè)占位圖锥债,并沒(méi)有做其他的事情陡蝇。但是我們?cè)诓榭?strong>GlideDrawableImageViewTarget的源碼的時(shí)候,我們發(fā)現(xiàn)了這么一個(gè)方法onResourceReady()哮肚,在這個(gè)方法中有這么一句代碼:
setResource(resource);
接著看看setResource():
public void setResource(GlideDrawable resource) {
view.setImageDrawable(resource);
}
這里的resource我們猜應(yīng)該就是圖片資源了登夫,也會(huì)是說(shuō)這里所做的事情就是最后將圖片呈現(xiàn)在ImageView上,但程序究竟是怎么到這里的呢允趟,我們想到了上面的getEngine()方法恼策,于是我們來(lái)看看這里所做的事情:
Engine getEngine() {
return engine;
}
這個(gè)Engine又是一個(gè)非常重要的類,我們來(lái)看看這個(gè)類的官方介紹:
Responsible for starting loads and managing active and cached resources.
我們發(fā)現(xiàn)這個(gè)類就是真正用來(lái)管理加載的類潮剪。但是這個(gè)不是我這篇文章的重點(diǎn)涣楷,關(guān)于它所作的事情我會(huì)在后面的文章中對(duì)它進(jìn)行簡(jiǎn)析。既然這個(gè)Engine對(duì)象是用來(lái)加載資源的抗碰,那么我們就想到了一開始的那個(gè)上面另外一個(gè)要記住的model狮斗,看看它們是怎么運(yùn)用的。要想知道這到底是怎么使用的弧蝇,我在這里貼出最重要的一段:
private void onLoadComplete(Resource resource) {
manager.onResourceReady(resource);
}
這個(gè)方法是EngineRunnable類中的情龄,這個(gè)類從名字就可以看出來(lái)它的作用就是響應(yīng)Engine的。而這里的onResourceReady()則是觸發(fā)了GenericRequest中的一個(gè)回調(diào)onResourceReady():
public void onResourceReady(Resource<?> resource) {
......
onResourceReady(resource, (R) received);
}
這里又調(diào)用了該類中的一個(gè)重載方法:
private void onResourceReady(Resource<?> resource, R result) {
......
if (requestListener == null || !requestListener.onResourceReady(result, model, target, loadedFromMemoryCache,
isFirstResource)) {
......
}
notifyLoadSuccess();
......
}
這里我們看到了捍壤,這個(gè)方法使用到了model骤视,而這個(gè)方法則屬于一個(gè)RequestListener回調(diào)接口,這個(gè)回調(diào)接口究竟會(huì)在哪里被調(diào)用呢鹃觉,其實(shí)就是我們上面提到的GlideDrawableImageViewTarget的onResourceReady()专酗,而在這個(gè)方法中,另一個(gè)參數(shù)target在這里的實(shí)際類型就是GlideDrawableImageViewTarget盗扇。到這里我們終于是弄明白整個(gè)圖片資源的加載過(guò)程了祷肯。
這里用了大量的篇幅大致地給大家介紹了一下Glide的大致加載流程沉填,但是在這其中我們還有很多關(guān)于圖片加載的所必需弄懂的細(xì)節(jié)并沒(méi)有進(jìn)行介紹,但是這篇文章就先到這里佑笋,關(guān)于這些東西我會(huì)在后續(xù)的文章中盡我所能地分析給大家翼闹。