Glide的簡介就不多說了,只要記住這是Google推薦AndroidDev使用的圖片開源框架就好了。直接進(jìn)入正題,看看Glide的設(shè)計(jì)到底有何精妙之處,為何獲得了Google的青睞?
一個(gè)最簡單的Glide圖片加載邏輯舉例:
Glide.with(context).load(url).into(imageView);
我們的分析會(huì)以Glide3.8.0版本為例,基于此行代碼展開,分別分析with()、load()、into()三個(gè)方法內(nèi)部的邏輯。
一、基礎(chǔ)概念
Glide中涉及幾個(gè)概念,為便于理解,先粗略解釋:
1.Model
指的是對(duì)圖片源的封裝。在AndroidDev中,比較常見的就是網(wǎng)絡(luò)圖片地址、本地文件或資源ID。比如,String url = "https://www.baidu.com/img/bd_logo1.png",這里的url經(jīng)過Glide內(nèi)部的封裝后,就可以理解為一個(gè)Model。
2.Data
指的是對(duì)Model處理后的數(shù)據(jù)源的封裝,通常是InputStream。而在Glide中,將Model處理為Data的類便是ModelLoader。比如,通過上文的"https://www.baidu.com/img/bd_logo1.png"而取得的圖片輸入流,就可以理解為Data。
3.Resource
拿到圖片的輸入流可以直接展示在UI上嗎?顯然不可以。在第2點(diǎn)中我們提及了Data,即輸入流,如果要將其展示就需要對(duì)Data進(jìn)行解碼,解碼后的數(shù)據(jù)就是Resource。比如,上文的圖片輸入流經(jīng)過解碼后成為一個(gè)Bitmap對(duì)象或Drawable對(duì)象,這個(gè)對(duì)象就可以理解為Resource。而擔(dān)任解碼任務(wù)的角色,被成為ResourceDecoder(資源解碼器)。
4.TransformedResource&TranscodedResource
有時(shí)候我們獲取到的Resource并不適合展示,而是需要經(jīng)過處理才能展示,比如需要裁剪變換等(如調(diào)用centerCrop()、fitCenter()),那么經(jīng)過如此變換后的Rescourse稱為TransformedResource。
我們知道Glide是可以展示靜態(tài)圖,也可以展示動(dòng)態(tài)圖(動(dòng)態(tài)Gif),而解碼后的靜態(tài)圖片和動(dòng)態(tài)圖片(例如drawable和gif-drawable)類型是不同的, 為了統(tǒng)一處理邏輯,Glide內(nèi)部將這兩種類型的對(duì)象再次封裝為統(tǒng)一的GlideBitmapDrawable,這里的GlideBitmapDrawable就可以理解為TranscodedResource。
5.Target
這個(gè)比較容易理解,即需要在哪個(gè)目標(biāo)上進(jìn)行展示,比如ImageView。而Glide內(nèi)部將ImageView再次進(jìn)行了封裝,封裝后對(duì)象就可以理解為Target。
綜上所述,一個(gè)完整的圖片處理及展示流程如下:

二、基本用法
直接看代碼和注釋:
Glide.with(context)
.load(url)
.placeholder(R.mipmap.ic_launcher)//圖片加載前的占位圖
.error(R.mipmap.ic_launcher)//圖片加載錯(cuò)誤的占位圖
.fitCenter()
.centerCrop()
.override(500, 500)//調(diào)整圖片大小
.skipMemoryCache(true)//跳過內(nèi)存緩存
.crossFade(1000)//漸變顯示時(shí)間
.diskCacheStrategy(DiskCacheStrategy.RESULT)//緩存處理后的圖像(如尺寸調(diào)整、裁剪后的圖像)
.diskCacheStrategy(DiskCacheStrategy.SOURCE)//緩存原尺寸的圖像
.diskCacheStrategy(DiskCacheStrategy.ALL)//緩存所有圖像
.diskCacheStrategy(DiskCacheStrategy.NONE)//跳過磁盤緩存
.priority(Priority.HIGH)//指定優(yōu)先級(jí)
.into(imageView);
三、with()源碼邏輯
跟進(jìn)Glide類中尋找with()方法,發(fā)現(xiàn)with()方法有多種重載,包括with(Context context)、with(Activity activity)、with(Fragment fragment)等等。Glide之所以設(shè)計(jì)如此之多的with()方法重載,其目的在于將圖片的加載與傳入的Context組件或Fragment的生命周期相關(guān)聯(lián)。比如,當(dāng)用戶關(guān)閉當(dāng)前Activity,那么即使該Activity有正在進(jìn)行中的圖片網(wǎng)絡(luò)請(qǐng)求,Glide也會(huì)隨之取消該網(wǎng)絡(luò)請(qǐng)求。如果傳入的是ApplicationContext,那么網(wǎng)絡(luò)請(qǐng)求會(huì)持續(xù)進(jìn)行,直至App進(jìn)程被銷毀。
這里以with(Context context)為例看一下源碼實(shí)現(xiàn),其他重載方法邏輯基本一致:
Glide.java
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
RequestManager類是Glide中用來處理圖片加載請(qǐng)求的管理類。RequestManagerRetriever類是用來創(chuàng)建和管理RequestManager對(duì)象的,其get()方法獲取了RequestManagerRetriever實(shí)例。繼續(xù)追蹤源碼,查看RequestManagerRetriever類中g(shù)et()方法的邏輯。
RequestManagerRetriever.java
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
在get()方法中,對(duì)Context的類型進(jìn)行了區(qū)分,有多種重載。我們主要分析一下Application和Activity類型的方法參數(shù),其他類型的參數(shù)讀者可以自行追蹤源碼。
RequestManagerRetriever.java
private RequestManager getApplicationManager(Context context) {
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
applicationManager = new RequestManager(context.getApplicationContext(),
new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
}
}
}
return applicationManager;
}
上述get(Application context)的方法中采取了雙重鎖單例模式獲取了一個(gè)RequestManager對(duì)象??梢园l(fā)現(xiàn),Glide在RequestManager的構(gòu)造方法中傳入了ApplicationLifecycle的實(shí)例,其作用是將RequestManager與Application生命周期綁定。
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public RequestManager get(Activity activity) {
if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm);
}
}
上述get(Activity context)的方法中,首先進(jìn)行了線程判斷,如果在非主線程的情況下,返回了get(Application context)類型的RequestManager,而在主線程的情況下,通過該Activity context獲取到了相關(guān)聯(lián)的FragmentManager。這是Glide設(shè)計(jì)精妙之處之一,為什么要獲取FragmentManger呢?繼續(xù)追蹤源碼到fragmentGet(activity,fm)中。
RequestManagerRetriever.java
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}
分析一下fragmentGet()的邏輯。首先,方法第一行g(shù)etRequestManagerFragment()返回了RequestManagerFragment的實(shí)例current。RequestManagerFragment是啥?其實(shí)這是Glide封裝的Fragment,這里當(dāng)作Fragment來理解。先來截取部分RequestManagerFragment類的代碼:
RequestManagerFragment.java
public class RequestManagerFragment extends Fragment {
......
private final ActivityFragmentLifecycle lifecycle;
private RequestManager requestManager;
public RequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
/**
* Sets the current {@link com.bumptech.glide.RequestManager}.
*
* @param requestManager The request manager to use.
*/
public void setRequestManager(RequestManager requestManager) {
this.requestManager = requestManager;
}
ActivityFragmentLifecycle getLifecycle() {
return lifecycle;
}
/**
* Returns the current {@link com.bumptech.glide.RequestManager} or null if none exists.
*/
public RequestManager getRequestManager() {
return requestManager;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
}
對(duì)RequestManagerFragment劃重點(diǎn):
1.含有一個(gè)RequestManager類型的成員變量requestManager,通過getRequestManager()返回,通過setRequestManager()賦值。
即每個(gè)RequestManagerFragment對(duì)象都與一個(gè)RequestManager對(duì)象綁定。
2.含有一個(gè)ActivityFragmentLifecycle類型的成員變量lifecycle。通過對(duì)lifecycle實(shí)現(xiàn)的LifecycleListener接口回調(diào)來監(jiān)聽其生命周期,可以發(fā)現(xiàn)在RequestManagerFragment類的onStart()、onStop()、onDestroy()方法中對(duì)其進(jìn)行了調(diào)用。
即lifecycle對(duì)象實(shí)現(xiàn)了對(duì)RequestManagerFragment實(shí)例的生命周期監(jiān)聽。
回到fragmentGet()方法中,調(diào)用RequestManagerFragment中的getRequestManager()方法返回與其綁定的RequestManager對(duì)象(成員變量),如果為null(沒有與其綁定的RequestManager對(duì)象),則創(chuàng)建一個(gè)RequestManager對(duì)象,并調(diào)用setRequestManager()將其與RequestManagerFragment綁定。至此實(shí)現(xiàn)了RequestManagerFragment對(duì)象與RequestManager對(duì)象的一一綁定。
現(xiàn)在思考一個(gè)問題,Glide如何監(jiān)聽目標(biāo)Activity或Fragment的生命周期?上文已經(jīng)說明,根據(jù)傳入Glide的Context不同,Glide會(huì)監(jiān)聽其生命周期,根據(jù)生命周期管理圖片的網(wǎng)絡(luò)請(qǐng)求。
Glide直接監(jiān)聽Activity并不方便。那么在這里,Glide采用了另外的方法:
1.在Activity或Fragment的上層添再加一個(gè)Fragment,也就是上文一直在分析的RequestManagerFragment。這個(gè)Fragment并沒有覆寫createFragmentView(),即這是一個(gè)無UI的Fragment,當(dāng)添加了該Fragment,用戶是無法感知到的。
2.我們知道依附于Activity的Fragment有與被依附的Activity相關(guān)聯(lián)的生命周期,監(jiān)聽Fragment的生命周期也就是獲取到了被依附的Activity的生命周期。上文已經(jīng)劃過重點(diǎn):RequestManagerFragment通過接口回調(diào)的方式,在onStart()、onStop()、onDestroy()中調(diào)用了ActivityFragmentLifecycle的相應(yīng)生命周期方法,實(shí)現(xiàn)了對(duì)其生命周期的監(jiān)聽。
3.如果傳入Glide.with()參數(shù)為Fragment,那么處理邏輯同上。大家應(yīng)該也在Fragment中添加過Fragment吧?Glide同樣監(jiān)聽了RequestManagerFragment的生命周期。
4.每個(gè)RequestManagerFragment對(duì)象又與RequestManager對(duì)象一一綁定。至此,所有疑問解開: