首頁>技術>

本文是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);    }}@Overridepublic 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的相應方法來處理:

@Overridepublic 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();    }}

呼叫這個方法將會把所有後裔的請求同時一起處理。

143

Android

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 大牛耗時一年:深入探索 Android 包體積優化,共三萬字建議收藏下