原文連結:Glide核心設計一:皮皮蝦,我們走
引言
皮皮蝦,又名蝦姑,是淡水中的強者。其頭部的兩個錘節,可以輕易破壞貝類的外殼,身體上的步足可以保證快速移動。這些優秀的品質,使它被表情包盯上。
Glide,作為Android最優秀的圖片載入框架之一,能和Activity和Fragment的生命週期繫結,是區別於其它網路框架的核心特徵,也是本文分析的重點。
我們將此特徵和皮皮蝦表情包做一個類比:
圖片網路請求緊跟Activity、Fragment的生命週期,當頁面不可互動時自動停止載入,當回到可互動狀態時,繼續載入。就像表情包(Activity、Fragment)控制皮皮蝦(圖片請求)一樣。
框架設計
簡單使用
Glide.with(Context).load(String).into(ImageView)可實現從網路中獲取圖片並展示到ImageView當中。其中和頁面作生命週期繫結的主要入口是Glide.with(Context)。按照一般的分析邏輯應該先分析原始碼,才得出結論,但因一入原始碼深似海,不利於整體把握,所以先給出結論。Glide.with(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.
由此可知,該類就是用於將請求和Activity或Framgent的生命週期做繫結。
類圖
將和生命週期相關的類圖如下(省略大部分類的變數和方法):
類的簡單介紹
- RequestManagerRetriever:該類用於建立RequestManager或在Activity、Fragment中找出已建立的RequestManager,RequestManagerRetriever是一個單例。
- RequestManagerFragment:繼承Fragment,不可見,僅用於儲存RequestManager,還有一個SupportRequestManagerFragment繼承v4包的Fragment,功能類似。
- LifecycleListener:用於監聽Activity、Fragment的生命週期事件。
- Lifecycle:用於新增LifecycleListener。
- ActivityFragmentLifecycle:實現Livecycle介面,用於通知Activity、Fragment的生命週期事件。
- RequestTracker:該類用於跟蹤、取消和重新啟動執行中、已完成和失敗的請求。
- ConnectivityMonitor: 監聽網路事件的介面,當網路狀態發生變化時,影響網路請求狀態,繼承LifecycleListener。
- DefaultConnectivityMonitor: ConnectivityMonitor的實現類,實現監聽網路狀態的邏輯。
- RequestManagerConnectivityListener: 實現ConnectivityListener介面,將網路事件傳遞給RequestTracker。
類的聯絡
以上對各類有一個簡單的瞭解,接下來將重點講清楚各類之間的聯絡。整個生命週期的繫結分為四部分。
- 呼叫Glide.with(Context),根據傳入的Context型別建立RequestManager。Context可以為Activity、Fragment和Application。
- 在傳入的引數Activity、或者Fragment中,新增一個不可見的Fragment,監聽不可見Fragment的生命週期並將該事件傳遞給和Fragment一一繫結的RequestManager。
- RequestManager監聽到生命事件後,管理圖片請求做出響應。
- 監聽當網路從無到有時,RequestManager要重新啟動圖片請求。
程式碼解讀
根據以上內容可直接跟程式碼可跳過以下內容,印象更加深刻。
第一部分:Glide.with(Context)
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
`複製程式碼
呼叫RequestManagerRetriever的get方法如下:
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) { //傳入的是Fragment
return get((FragmentActivity) context);
} else if (context instanceof Activity) { //傳入的是Acitivity
return get((Activity) context);
} else if (context instanceof ContextWrapper) { //傳入的是Application
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}複製程式碼
以傳入引數為Activity型別為例,程式碼如下:
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(); //獲取FragmentManager
return fragmentGet(activity, fm);
}
}複製程式碼
主要呼叫fragmentGet方法,程式碼如下:
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
RequestManagerFragment current = getRequestManagerFragment(fm);
RequestManager requestManager = current.getRequestManager(); //根據RequestManagerFragment獲取RequestManager,一個RequestManagerFragment包含一個RequestManager
if (requestManager == null) { //若RequestManager為空,則新建一個並且設定到RequestManagerFragment中
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
current.setRequestManager(requestManager);
}
return requestManager;
}複製程式碼
getRequestManagerFragment(fm)函式主要是根據FragmentManager獲取Fragment,程式碼如下:
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); //通過Tag查詢
if (current == null) { //若為空,從快取pendingRequestManagerFragments中查詢
current = pendingRequestManagerFragments.get(fm);
if (current == null) { //快取中也不存在,則新建一個RequestManagerFragment,並且新增到頁面中。
current = new RequestManagerFragment();
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}複製程式碼
以上就是根據傳入的Context型別建立RequestManager的程式碼部分。
第二部分:監聽不可見Fragment的生命週期並傳遞給RequestManager
新增不可見Fragment的目的,就是因為該Fragment和父類的Activity具有同樣的生命週期,無須改動原有Activity的程式碼,即可實現生命週期的監聽。
RequestManagerFragment生命週期相關的程式碼如下:
@Override
public void onStart() {
super.onStart();
lifecycle.onStart(); //執行lifecycle的onStart方法
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();//執行lifecycle的onStop方法
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();//執行lifecycle的onDestroy方法
}複製程式碼
可以看出,Fragment的宣告週期的監聽都轉移到型別是ActivityFragmentLifecycle的變數lifecycle中的對應方法執行。檢視ActivityFragmentLifecycle的程式碼:
void onStart() {
isStarted = true;
//迴圈set集合lifecycleListeners中所有LifecycleListener,執行對應的onStart
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
//省略onStop()和onDestroy()方法,和onStart()方法類似。複製程式碼
set集合的LifecycleListener是如何新增進去的,看ActivityFragmentLifecycle中的程式碼:
@Override
public void addListener(LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {//如果當前頁面已經被destroy,則呼叫對應的onDestroy
listener.onDestroy();
} else if (isStarted) {//如果當前頁面已經開啟,則呼叫對應的onStart
listener.onStart();
} else { //其他情況呼叫onStop方法
listener.onStop();
}
}複製程式碼
addListener(LifecycleListener listener)方法是介面Lifecycle的方法。RequestManagerFragment提供一個公有方法:
ActivityFragmentLifecycle getLifecycle() {
return lifecycle;
}複製程式碼
回看第一部分建立RequestManager時:
requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());複製程式碼
RequestManagerFragment中的Lifecycle作為RequestManager的建構函式的引數傳遞給RequestManager。RequestManager建構函式如下:
RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();
//監聽網路變化的類
ConnectivityMonitor connectivityMonitor = factory.build(context,
new RequestManagerConnectivityListener(requestTracker));
// If we're the application level request manager, we may be created on a background thread. In that case we
// cannot risk synchronously pausing or resuming requests, so we hack around the issue by delaying adding
// ourselves as a lifecycle listener by posting to the main thread. This should be entirely safe.
if (Util.isOnBackgroundThread()) {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
//在主執行緒中將當前類實現的LifecycleListener新增到lifecycle中。
lifecycle.addListener(RequestManager.this);
}
});
} else {
//在主執行緒中將當前類實現的LifecycleListener新增到lifecycle中。
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
}複製程式碼
由此可見,lifecycle新增的就是RequestManager實現的LifecycleListener介面。
第三部分:RequestManager實現LifecycleListener
接著檢視RequestManager實現LifecycleListener的方法:
@Override
public void onStart() {
// onStart might not be called because this object may be created after the fragment/activity's onStart method.
resumeRequests();
}
@Override
public void onStop() {
pauseRequests();
}
@Override
public void onDestroy() {
requestTracker.clearRequests();
}複製程式碼
繼續進入resumeRequests()、pauseRequests()和requestTracker.clearRequests()方法可知,都是呼叫RequestTracker相應的方法,RequestTracker類包含一個集合的Request,該集合包含一個Activity獲取一個
Fragment的所以圖片請求,將根據RequestManagerFragment的生命週期,統一管理圖片請求。
第四部分:監聽網路狀態並作出相應
RequestManager的建構函式有如下方法:
//省略部分程式碼...
//監聽網路變化的類
ConnectivityMonitor connectivityMonitor = factory.build(context,
new RequestManagerConnectivityListener(requestTracker));
//省略部分程式碼...
lifecycle.addListener(connectivityMonitor);
//省略部分程式碼...複製程式碼
以上程式碼可看出,ConnectivityMonitor也實現了LifecycleListener。繼續跟蹤程式碼發現,factory的例項是ConnectivityMonitorFactory,在該工廠中會檢查網路許可權,同時建立ConnectivityMonitor的例項DefaultConnectivityMonitor。LifecycleListener介面的實現如下:
@Override
public void onStart() {
register(); //register()方法為註冊廣播監聽網路變化
}
@Override
public void onStop() {
unregister(); //解除監聽廣播
}
@Override
public void onDestroy() {
// Do nothing.
}複製程式碼
廣播接收器程式碼如下:
private final BroadcastReceiver connectivityReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
boolean wasConnected = isConnected;
isConnected = isConnected(context);
if (wasConnected != isConnected) { //當網路狀態發生變化時,才呼叫listener.onConnectivityChanged()方法
listener.onConnectivityChanged(isConnected);
}
}
};複製程式碼
ConnectivityListener 的例項的型別是RequestManager的內部類,程式碼如下:
private static class RequestManagerConnectivityListener implements ConnectivityMonitor.ConnectivityListener {
private final RequestTracker requestTracker;
public RequestManagerConnectivityListener(RequestTracker requestTracker) {
this.requestTracker = requestTracker;
}
@Override
public void onConnectivityChanged(boolean isConnected) {
if (isConnected) { //如果當前狀態是連結狀態
requestTracker.restartRequests(); //重新開啟圖片請求
}
}
}複製程式碼
小結
以上就是Glide實現圖片載入和Activity、Fragment生命週期繫結的全部分析。會發現使用了觀察者模式和工廠模式進行解耦,其中建立一個不可見的Fragment設定到需要被監控生命週期的Activity、Fragment中,最為精彩。接下來將分析Glide核心設計二:圖片快取。敬請期待。