Glide核心設計一:皮皮蝦,咱們走

原文連接:Glide核心設計一:皮皮蝦,咱們走java

引言

皮皮蝦,又名蝦姑,是淡水中的強者。其頭部的兩個錘節,能夠輕易破壞貝類的外殼,身體上的步足能夠保證快速移動。這些優秀的品質,使它被表情包盯上。android

Glide,做爲Android最優秀的圖片加載框架之一,能和Activity和Fragment的生命週期綁定,是區別於其它網絡框架的核心特徵,也是本文分析的重點。git

咱們將此特徵和皮皮蝦表情包作一個類比:
github

皮皮蝦和Glide類比

圖片網絡請求緊跟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的生命週期作綁定。app

類圖

將和生命週期相關的類圖以下(省略大部分類的變量和方法):
框架

聲明週期綁定類圖

類的簡單介紹

  1. RequestManagerRetriever:該類用於建立RequestManager或在Activity、Fragment中找出已建立的RequestManager,RequestManagerRetriever是一個單例。
  2. RequestManagerFragment:繼承Fragment,不可見,僅用於保存RequestManager,還有一個SupportRequestManagerFragment繼承v4包的Fragment,功能相似。
  3. LifecycleListener:用於監聽Activity、Fragment的生命週期事件。
  4. Lifecycle:用於添加LifecycleListener。
  5. ActivityFragmentLifecycle:實現Livecycle接口,用於通知Activity、Fragment的生命週期事件。
  6. RequestTracker:該類用於跟蹤、取消和從新啓動執行中、已完成和失敗的請求。
  7. ConnectivityMonitor: 監聽網絡事件的接口,當網絡狀態發生變化時,影響網絡請求狀態,繼承LifecycleListener。
  8. DefaultConnectivityMonitor: ConnectivityMonitor的實現類,實現監聽網絡狀態的邏輯。
  9. RequestManagerConnectivityListener: 實現ConnectivityListener接口,將網絡事件傳遞給RequestTracker。

類的聯繫

以上對各種有一個簡單的瞭解,接下來將重點講清楚各種之間的聯繫。整個生命週期的綁定分爲四部分。ide

  1. 調用Glide.with(Context),根據傳入的Context類型建立RequestManager。Context能夠爲Activity、Fragment和Application。
  2. 在傳入的參數Activity、或者Fragment中,添加一個不可見的Fragment,監聽不可見Fragment的生命週期並將該事件傳遞給和Fragment一一綁定的RequestManager。
  3. RequestManager監聽到生命事件後,管理圖片請求作出響應。
  4. 監聽當網絡從無到有時,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核心設計二:圖片緩存。敬請期待。

相關文章
相關標籤/搜索