作者:他的大姨父
鏈接:https://www.jianshu.com/p/317b2d6bde1b
本文是Glide源碼解析系列的第一篇,通過這篇文檔,將可以了解到:
- 1.Glide如何綁定Activity、Fragment生命周期。
- 2.Glide如何監聽內存變化、網絡變化。
- 3.Glide如何處理請求的生命周期。
1.0 生命周期相關UML類圖
2.0 生命周期綁定
Glide生命周期綁定是從入口單例類Glide開始的,通過with()多個重載方法來實現對生命周期的綁定工作。
public static RequestManager with(Fragment fragment) public static RequestManager with(FragmentActivity activity) public static RequestManager with(Activity activity) public static RequestManager with(Context context)
以Activity的參數為例:
public static RequestManager with(Activity activity) { RequestManagerRetriever retriever = RequestManagerRetriever.get(); return retriever.get(activity); }
RequestManagerRetriever是一個單例類,可以理解為一個工廠類,通過get方法接收不同的參數,來創建RequestManager。
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); } } public RequestManager get(android.app.Fragment fragment) { if (fragment.getActivity() == null) { throw new IllegalArgumentException("You cannot start a load on a fragment before it is attached"); } if (Util.isOnBackgroundThread() || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { return get(fragment.getActivity().getApplicationContext()); } else { android.app.FragmentManager fm = fragment.getChildFragmentManager(); return fragmentGet(fragment.getActivity(), fm); } }
如果是在子線程進行的with操作,那么Glide將默認使用ApplicationContext,可以理解為不對請求的生命周期進行管理,通過Activity拿到FragmentManager,並將創建RequestManager的任務傳遞下去。最終都走到了fragmentGet方法,注意細微區別是Activity傳的參數的是Activity的FragmentManager,Fragment傳的參數的是ChildFragmentManager,這兩者不是一個東西。
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) { //獲取RequestManagerFragment,並獲取綁定到這個fragment的RequestManager RequestManagerFragment current = getRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { //如果獲取RequestManagerFragment還沒有綁定過RequestManager,那么就創建RequestManager並綁定到RequestManagerFragment requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager; }
2.0.1 創建RequestManagerFragment
這個方法創建了一個fragment,並且創建並綁定了一個RequestManager,看看getRequestManagerFragment如何獲取的RequestManagerFragment。
RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) { //嘗試根據id去找到此前創建的RequestManagerFragment RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG); if (current == null) { //如果沒有找到,那么從臨時存儲中尋找 current = pendingRequestManagerFragments.get(fm); if (current == null) { //如果仍然沒有找到,那么新建一個RequestManagerFragment,並添加到臨時存儲中。 //然后開啟事務綁定fragment並使用handler發送消息來將臨時存儲的fragment移除。 current = new RequestManagerFragment(); pendingRequestManagerFragments.put(fm, current); fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss(); handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget(); } } return current; }
這里有個問題,為什么需要使用pendingRequestManagerFragments這樣一個集合來臨時存儲一下fragment,然后又馬上通過handler發送消息移除?這其實是跟主線程的Looper機制和Fragment的事務機制有關的(點擊這里查看Fragment事務流程分析)。我們知道,android中的主線程是一個閉環,通過Handler發送消息到MessageQueue,然后通過Looper輪詢獲取消息並交給Handler處理(點擊這里查看Activity啟動流程分析)。如下面一個常見場景:
Glide.with(this).load(url_1).into(mImageView_1); Glide.with(this).load(url_2).into(mImageView_2);
這段代碼通過Glide加載了兩張圖片並設置到了兩個ImageView上,當以上代碼塊執行時,其所屬的代碼群的Message剛剛從MessageQueue中取出正在被處理,我們假設這個Message為m1,並且這個MessageQueue中沒有其他消息。此時情形是這樣的:
當代碼執行到getRequestManagerFragment這個方法時,會通過開啟事務的方式來綁定這個fragment到activity,相關源碼如下(有興趣了解的點擊這里查看Fragment事務流程分析),這個方法在FragmentManagerImpl.java中:
public void enqueueAction(Runnable action, boolean allowStateLoss) { if (!allowStateLoss) { checkStateLoss(); } synchronized (this) { if (mDestroyed || mHost == null) { throw new IllegalStateException("Activity has been destroyed"); } if (mPendingActions == null) { mPendingActions = new ArrayList<Runnable>(); } mPendingActions.add(action); if (mPendingActions.size() == 1) { mHost.getHandler().removeCallbacks(mExecCommit); mHost.getHandler().post(mExecCommit); } } }
這里的mHost其實就是activity創建的,並且持有activity以及mMainHandler的引用,根據上述代碼可以知道,其實綁定fragment的操作最終是通過主線程的handler發送消息處理的,我們假設這個消息為m2。然后handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();這句代碼發送的消息為m3。那么當Glide.with(this).load(url_1).into(mImageView_1);這句代碼執行這里時,消息隊列有了變化:
但是m2這個消息並不會馬上被處理,這是因為m1還有代碼還沒有執行完畢,也就是說這個fragment並不會馬上被綁定,此時m1繼續向下執行到第二句代碼Glide.with(this).load(url_2).into(mImageView_2);當這句代碼走到getRequestManagerFragment時,如果在m1時,我們不將fragment臨時存儲在pendingRequestManagerFragments中,由於m2還沒有被處理,那么
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
必然是找不到這個fragment的,那么就會導致重新創建一個新的重復的fragment,並開啟事務綁定,這顯然是不合情理的,因為Glide需要保證rootFragment的唯一性,rootFragment即fragment依附或者沒有fragment依附的activity所創建的最上層RequestManagerFragment。
接着往下看RequestManagerFragment的構造方法做了什么。
public RequestManagerFragment() { this(new ActivityFragmentLifecycle()); }
直接創建一個ActivityFragmentLifecycle,這個類實際是一個生命周期回調的管理類,實現了Lifecycle接口。所有的LifecycleListener會添加到一個集合中,當RequestManagerFragment生命周期方法觸發時,會調用ActivityFragmentLifecycle相應生命周期方法,這個方法然后再遍歷調用所有LifecycleListener的生命周期方法,以onStart生命周期方法為例,RequestManagerFragment中:
public void onStart() { super.onStart(); lifecycle.onStart(); }
然后ActivityFragmentLifecycle中:
void onStart() { isStarted = true; for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) { lifecycleListener.onStart(); } }
2.0.2 rootRequestManagerFragment
上面UML圖上,可以知道RequestManagerFragment還有一個rootRequestManagerFragment的成員變量,Glide每創建一個RequestManagerFragment,都會嘗試實例化rootRequestManagerFragment,這個fragment即頂級的Activity所創建的RequestManagerFragment,相關代碼:
public void onAttach(Activity activity) { super.onAttach(activity); rootRequestManagerFragment = RequestManagerRetriever.get() .getRequestManagerFragment(getActivity().getFragmentManager()); if (rootRequestManagerFragment != this) { rootRequestManagerFragment.addChildRequestManagerFragment(this); } } @Override public void onDetach() { super.onDetach(); if (rootRequestManagerFragment != null) { rootRequestManagerFragment.removeChildRequestManagerFragment(this); rootRequestManagerFragment = null; } }
可以看到,不管當前的RequestManagerFragment是通過何種方式創建的,都會在OnAttach時,拿到當前所綁定的Activity的FragmentManager來初始化一個RequestManagerFragment,這個RequestManagerFragment有可能是自身,有可能已經被初始化過了,比如是通過with(Activity activity)的方式初始化的,那么很顯然
RequestManagerRetriever.get().getRequestManagerFragment(getActivity().getFragmentManager());
這句代碼拿到的會是自己本身,而如果是通過with(Fragment fragment)的形式創建的,rootRequestManagerFragment將指向當前fragment綁定到Activity所綁定的RequestManagerFragment,如果該Activity沒有綁定過,那么會開啟事務綁定一個RequestManagerFragment。並且如果自己不是rootRequestManagerFragment的話,那么將會把自己保存到rootRequestManagerFragment中的一個集合:
private void addChildRequestManagerFragment(RequestManagerFragment child) { childRequestManagerFragments.add(child); }
簡而言之,Glide會為Activity創建一個RequestManagerFragment做為rootFragment,並保存該Activity底下所有Fragment(如果有的話)所創建的RequestManagerFragment。
2.0.3 RequestManagerTreeNode
RequestManagerFragment初始化時,還會初始化RequestManagerTreeNode,顧名思義,這個類是用來保存請求樹節點的,比如一個Activity采用Viewpager + Fragment的形式,而里面的Fragment又是一個ViewPager + Fragment的形式,這個時候,假設其中一個RequestManagerFragment生命周期方法走了,怎么知道哪些RequestManagerFragment綁定的LifeCycle應該得到調用呢?理想的情況是,應該讓綁定該RequestManagerFragment的Fragment所有的子Fragment的RequestManagerFragment的生命周期得到調用,比如如下場景中,Activity中各有兩個Fragment,兩個Fragment又各有兩個子Fragment,在所有Fragment中,均通過with(this)的方式來加載圖片,經過之前的分析我們可以知道的是,ROOT RMF 中會保存有6個RMF(RMF即RequestManagerFragment):
當如果F1 RMF生命周期做出反應時,因為RequestManagerFragment是無界面的,所以可以理解為F1的生命周期做出反應。我們希望F11和F12所綁定的RequestManagerFragment也要立即做出反應。但是F2以及其底下的RequestManagerFragment則不應響應對應生命周期事件,我們知道任何一個RequestManagerFragment可以通過rootRequestManagerFragment拿到這6個RMF,繼而拿到其所對應的RequestManager,那么怎么去確定F11 RMF 和 F12 RMF呢?這就是RequestManagerTreeNode干的事情了,RequestManagerFragment中的非靜態內部類FragmentRequestManagerTreeNode實現了RequestManagerTreeNode:
private class FragmentRequestManagerTreeNode implements RequestManagerTreeNode { @Override public Set<RequestManager> getDescendants() { Set<RequestManagerFragment> descendantFragments = getDescendantRequestManagerFragments(); HashSet<RequestManager> descendants = new HashSet<RequestManager>(descendantFragments.size()); for (RequestManagerFragment fragment : descendantFragments) { if (fragment.getRequestManager() != null) { descendants.add(fragment.getRequestManager()); } } return descendants; } }
這個類做的事情比較簡單,調用外部類RequestManagerFragment的方法getDescendantRequestManagerFragments拿到所有的“后裔”Fragment,然后再取出它的RequestManager,然后集合裝起來返回,這里的后裔在前面的例子中,指的就是F11 RMF 和 F12 RMF,看看getDescendantRequestManagerFragments是怎么拿到的F11和F12:
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) public Set<RequestManagerFragment> getDescendantRequestManagerFragments() { //如果自己是rootFragment,那么直接返回childRequestManagerFragments if (rootRequestManagerFragment == this) { return Collections.unmodifiableSet(childRequestManagerFragments); } else if (rootRequestManagerFragment == null || Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { // Pre JB MR1 doesn't allow us to get the parent fragment so we can't introspect hierarchy, so just // return an empty set. return Collections.emptySet(); } else { HashSet<RequestManagerFragment> descendants = new HashSet<RequestManagerFragment>(); for (RequestManagerFragment fragment //遍歷取出rootFragment中的RMF,並獲取到其parentFragment,找出后裔。 : rootRequestManagerFragment.getDescendantRequestManagerFragments()) { if (isDescendant(fragment.getParentFragment())) { descendants.add(fragment); } } return Collections.unmodifiableSet(descendants); } }
看看isDescendant方法是如何判斷的:
private boolean isDescendant(Fragment fragment) { Fragment root = this.getParentFragment(); while (fragment.getParentFragment() != null) { if (fragment.getParentFragment() == root) { return true; } fragment = fragment.getParentFragment(); } return false; }
依上面的例子,當遍歷到F11 RMF時,參數傳遞過來的是F11,root 則為F1,F11再拿到parent,也是F1,返回true,F12 RMF類似也返回true;
當遍歷到F21 RMF時,參數傳入F21,root仍是F1,此時F21再怎么拿Parent也不可能是root,返回false。
簡而言之,RequestManagerTreeNode用來獲取綁定該RequestManagerFragment的Fragment的所有子Fragment所綁定的RequestManagerFragment所綁定的RequestManager
2.0.4 RequestManager
上面一直在說RequestManagerFragment,下面回到FragmentGet方法中,再貼一次,免得上翻麻煩:
RequestManager fragmentGet(Context context, android.app.FragmentManager fm) { //獲取RequestManagerFragment,並獲取綁定到這個fragment的RequestManager RequestManagerFragment current = getRequestManagerFragment(fm); RequestManager requestManager = current.getRequestManager(); if (requestManager == null) { //如果獲取RequestManagerFragment還沒有綁定過RequestManager,那么就創建RequestManager並綁定到RequestManagerFragment requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode()); current.setRequestManager(requestManager); } return requestManager; }
根據上面的UML圖,可以知道RequestManager是一個非常核心的類,並且還實現了LifecycleListener來處理請求的生命周期。上述代碼在創建RequestManager時,傳遞了3個參數,分別是context,前面分析過的初始化RequestManagerFragment所創建的LifeCycle和RequestManagerTreeNode。直接看RequestManager的構造函數:
public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) { this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory()); }
調用的另一個構造方法,並增加了兩個新的參數RequestTracker和ConnectivityMonitorFactory。
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() { lifecycle.addListener(RequestManager.this); } }); } else { lifecycle.addListener(this); } lifecycle.addListener(connectivityMonitor); }
RequestTracker即所有請求操作的真正處理者,所有Request的暫停取消執行操作都由RequestTracker來完成,如RequestManager暫停請求的實現:
public void pauseRequests() { Util.assertMainThread(); requestTracker.pauseRequests(); }
2.0.5 網絡狀態監測
請求生命周期的實現細節后面再說,暫時埋坑,先來看看ConnectivityMonitorFactory這個工廠生產了什么。
public class ConnectivityMonitorFactory { public ConnectivityMonitor build(Context context, ConnectivityMonitor.ConnectivityListener listener) { final int res = context.checkCallingOrSelfPermission("android.permission.ACCESS_NETWORK_STATE"); final boolean hasPermission = res == PackageManager.PERMISSION_GRANTED; if (hasPermission) { return new DefaultConnectivityMonitor(context, listener); } else { return new NullConnectivityMonitor(); } } }
很簡單,接收一個ConnectivityListener根據是否有監控網絡狀態的權限來創建相應的網絡監控器。
DefaultConnectivityMonitor也比較簡單,就是內部定義了一個廣播接收者,並且也實現了lifeCycleListener。在上面RequestManager的構造方法中,創建了一個RequestManagerConnectivityListener:
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(); } } }
這個listener很簡單,收到網絡狀態連接就重啟請求。然后通過工廠創建出了DefaultConnectivityMonitor,並把它添加到了lifecycle中。到這里,Glide監測網絡狀態來重啟請求的實現方式就呼之欲出了,大體步驟如下:
在相應的生命周期方法中,會調用lifecycle的生命周期方法,lifecycle會調用DefaultConnectivityMonitor所實現的相應生命周期方法來注冊及解除注冊網絡狀態的廣播接收者,收到廣播后,會回調之前傳遞的參數ConnectivityListener的onConnectivityChanged方法來處理Request。
2.0.6 內存狀態監測
RequestManager中還存有Glide這個入口類的實例,構造方法中直接獲取到的,用來對內存狀態的變更作出處理,比較簡單,看看流程便可以了,以onTrimMemory為例,
當RequestManagerFragment的onTrimMemory被調用時,會調用其綁定的RequetManager的相應方法來處理:
@Override public void onTrimMemory(int level) { // If an activity is re-created, onTrimMemory may be called before a manager is ever set. // See #329. if (requestManager != null) { requestManager.onTrimMemory(level); } }
然后RequestManager再調用Glide入口類的trimMemory來釋放更多內存:
public void onTrimMemory(int level) { glide.trimMemory(level); }
2.0.7 生命周期回調流程總結
在RequestManager構造方法中,還會將自身添加到LifeCycle中,這樣,整個流程就暢通了:
細心的可以發現,雖然在構造RequestManager時傳遞了參數RequestManagerTreeNode,但是在這個回調流程中,並沒有對所有后裔RMF的RequestManager進行調用,Glide默認確實是不會去調用,但這里並不意味着這些RequestManager不會被調用到,事實上,當前RMF生命周期被調用時,就意味后裔Fragment生命周期也會被調用,那么后裔Fragment這個流程仍然會走一遍,那么RequestManagerTreeNode到底有什么用呢?答案是沒用,完全沒用,如果只是簡單使用Glide的話。當然,RequestManager暴露了相關接口給開發者使用:
public void resumeRequestsRecursive() { Util.assertMainThread(); resumeRequests(); for (RequestManager requestManager : treeNode.getDescendants()) { requestManager.resumeRequests(); } }
調用這個方法將會把所有后裔的請求同時一起處理。
**推薦閱讀:[2017-2020歷年字節跳動Android面試真題解析(累計下載1082萬次,持續更新中)
](https://www.jianshu.com/p/7f9ade51232e)**
2020最新Android大廠高頻面試題解析大全(BAT TMD JD 小米)