Glide學(xué)習(xí)筆記

默認(rèn)情況下,Glide會在開始一個新的圖片請求(網(wǎng)絡(luò)請求)之前檢查以下多級緩存

1. 活動資源 (Active Resources) 
2. 內(nèi)存緩存 (Memory Cache) 
3. 資源類型(Resource Disk Cache)
4. 原始數(shù)據(jù) (Data Disk Cache)
活動資源:如果當(dāng)前對應(yīng)的圖片資源正在使用,則這個圖片會被Glide放入活動緩存。
內(nèi)存緩存:如果圖片最近被加載過,并且當(dāng)前沒有使用這個圖片,則會被放入內(nèi)存中
資源類型:  被解碼后的圖片寫入磁盤文件中,解碼的過程可能修改了圖片的參數(shù)(如:inSampleSize、inPreferredConfig)數(shù)據(jù))
原始數(shù)據(jù):  圖片原始數(shù)據(jù)在磁盤中的緩存(從網(wǎng)絡(luò)、文件中直接獲得的原始

在調(diào)用Glide.with(activity) .load(url) .into(imageView)時,Glide會首先從Active Resources查找當(dāng)前是否有對應(yīng)的活躍圖片,沒有則查找內(nèi)存緩存,沒有則查找資源類型,沒有則查找原始數(shù)據(jù)。


11462765-5ad875863445b4f1.webp.jpg

第一層 活動資源

活動資源是一個“引用計數(shù)”的圖片資源的弱引用集合。

因為同一張圖片可能在多個地方被同時使用,每一次使用都會將引用計數(shù)+1,而當(dāng)引用計數(shù)為0時候,則表示這個圖片沒有被使用也就是沒有強(qiáng)引用了。這樣則會將圖片從活動資源中移除,并加入內(nèi)存緩存。

/**
 * 引用計數(shù)為0回調(diào)
 * 將其從正在使用集合移除 并加入內(nèi)存緩存
  * @param key
 * @param resource
 */
@Override
public void onResourceReleased(Key key, Resource resource) {
    activeResource.deactivete(key);
    Glide.get(context).getBitmapPool().put(resource.getBitmap());
}

第二層 內(nèi)存緩存

內(nèi)存緩存默認(rèn)使用LRU(最近最少使用算法),當(dāng)資源從活動資源移除的時候,會加入此緩存。使用圖片的時候會主動從此緩存移除,加入活動資源。

public LruCache(int maxSize) {
    if (maxSize <= 0) {
        throw new IllegalArgumentException("maxSize <= 0");
    } else {
        this.maxSize = maxSize;
        this.map = new LinkedHashMap(0, 0.75F, true);
    }
}

LinkedHashMap的第三個參數(shù)為true,開啟自動排序,在使用此map進(jìn)行g(shù)et或者put的時候會自動排序,確保了最近最少使用的在尾端最先被刪除。

第三,四層 磁盤緩存

Resource緩存的是經(jīng)過解碼后的圖片。

Data緩存的則是圖像原始數(shù)據(jù)。同樣都是維護(hù)了一個LRU的算法

Bitmap復(fù)用

如果緩存都不存在,那么會從源地址獲得圖片(網(wǎng)絡(luò)/文件)。而在解析圖片的時候會需要BitmapPool(復(fù)用池),達(dá)到復(fù)用的效果


11462765-4ae3a04cdd66d3ac.webp.jpg
11462765-31d71dbda64060b2.webp.jpg

復(fù)用效果如上。在未使用復(fù)用的情況下,每張圖片都需要一塊內(nèi)存。而使用復(fù)用的時候,如果存在能被復(fù)用的圖片會重復(fù)使用該圖片的內(nèi)存。
所以復(fù)用并不能減少程序正在使用的內(nèi)存大小。Bitmap復(fù)用,解決的是減少頻繁申請內(nèi)存帶來的性能(抖動、碎片)問題。

BitmapPool是Glide中的Bitmap復(fù)用池,同樣適用LRU來進(jìn)行管理。
當(dāng)一個Bitmap從內(nèi)存緩存 被動 的被移除(內(nèi)存緊張、達(dá)到maxSize)的時候并不會被recycle。而是加入這個BitmapPool,只有從這個BitmapPool 被動被移除的時候,Bitmap的內(nèi)存才會真正被recycle釋放。

網(wǎng)絡(luò)加載

資源來源可能有url網(wǎng)絡(luò)下載,也可能是sd卡中資源加載。根據(jù)來源不同來分別使用對應(yīng)的方式進(jìn)行加載最終獲取得到inputstream流,再通過解碼器解碼inputstream來得到Bitmap。采用了策略模式,工廠模式,建造者模式根據(jù)不同的URI來生產(chǎn)對應(yīng)的加載器。解析出來的圖片資源會存入磁盤緩存,然后再存入到活動資源中!

生命周期管理

Glide生命周期綁定是從入口單例類Glide開始的,通過with()多個重載方法來實現(xiàn)對生命周期的綁定工作。

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的參數(shù)為例:

public static RequestManager with(Activity activity) {
    RequestManagerRetriever retriever = RequestManagerRetriever.get();
    return retriever.get(activity);
}

RequestManagerRetriever是一個單例類,可以理解為一個工廠類,通過get方法接收不同的參數(shù),來創(chuàng)建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);
    }
}

如果是在子線程進(jìn)行的with操作,那么Glide將默認(rèn)使用ApplicationContext,可以理解為不對請求的生命周期進(jìn)行管理,通過Activity拿到FragmentManager,并將創(chuàng)建RequestManager的任務(wù)傳遞下去。最終都走到了fragmentGet方法,注意細(xì)微區(qū)別是Activity傳的參數(shù)的是Activity的FragmentManager,F(xiàn)ragment傳的參數(shù)的是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,那么就創(chuàng)建RequestManager并綁定到RequestManagerFragment
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

創(chuàng)建RequestManagerFragment

這個方法創(chuàng)建了一個fragment,并且創(chuàng)建并綁定了一個RequestManager,看看getRequestManagerFragment如何獲取的RequestManagerFragment。

RequestManagerFragment getRequestManagerFragment(final android.app.FragmentManager fm) {
    //嘗試根據(jù)id去找到此前創(chuàng)建的RequestManagerFragment
    RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
    if (current == null) {
        //如果沒有找到,那么從臨時存儲中尋找
        current = pendingRequestManagerFragments.get(fm);
        if (current == null) {
            //如果仍然沒有找到,那么新建一個RequestManagerFragment,并添加到臨時存儲中。
            //然后開啟事務(wù)綁定fragment并使用handler發(fā)送消息來將臨時存儲的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;
}

接著往下看RequestManagerFragment的構(gòu)造方法做了什么。

public RequestManagerFragment() {
    this(new ActivityFragmentLifecycle());
}

直接創(chuàng)建一個ActivityFragmentLifecycle,這個類實際是一個生命周期回調(diào)的管理類,實現(xiàn)了Lifecycle接口。所有的LifecycleListener會添加到一個集合中,當(dāng)RequestManagerFragment生命周期方法觸發(fā)時,會調(diào)用ActivityFragmentLifecycle相應(yīng)生命周期方法,這個方法然后再遍歷調(diào)用所有LifecycleListener的生命周期方法,以onStart生命周期方法為例,RequestManagerFragment中:

public void onStart() {
    super.onStart(); 
    lifecycle.onStart();
}

然后ActivityFragmentLifecycle中:

void onStart() {
    isStarted = true;
    for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
        lifecycleListener.onStart();
    }
}

rootRequestManagerFragment

RequestManagerFragment還有一個rootRequestManagerFragment的成員變量,Glide每創(chuàng)建一個RequestManagerFragment,都會嘗試實例化rootRequestManagerFragment,這個fragment即頂級的Activity所創(chuàng)建的RequestManagerFragment,相關(guān)代碼:

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;
    }
}

可以看到,不管當(dāng)前的RequestManagerFragment是通過何種方式創(chuàng)建的,都會在OnAttach時,拿到當(dāng)前所綁定的Activity的FragmentManager來初始化一個RequestManagerFragment,這個RequestManagerFragment有可能是自身,有可能已經(jīng)被初始化過了,比如是通過with(Activity activity)的方式初始化的,那么很顯然

RequestManagerRetriever.get().getRequestManagerFragment(getActivity().getFragmentManager());

這句代碼拿到的會是自己本身,而如果是通過with(Fragment fragment)的形式創(chuàng)建的,rootRequestManagerFragment將指向當(dāng)前fragment綁定到Activity所綁定的RequestManagerFragment,如果該Activity沒有綁定過,那么會開啟事務(wù)綁定一個RequestManagerFragment。并且如果自己不是rootRequestManagerFragment的話,那么將會把自己保存到rootRequestManagerFragment中的一個集合:

private void addChildRequestManagerFragment(RequestManagerFragment child) {
    childRequestManagerFragments.add(child);
}

簡而言之,Glide會為Activity創(chuàng)建一個RequestManagerFragment做為rootFragment,并保存該Activity底下所有Fragment(如果有的話)所創(chuàng)建的RequestManagerFragment。

RequestManagerTreeNode

RequestManagerFragment初始化時,還會初始化RequestManagerTreeNode,顧名思義,這個類是用來保存請求樹節(jié)點的,比如一個Activity采用Viewpager + Fragment的形式,而里面的Fragment又是一個ViewPager + Fragment的形式,這個時候,假設(shè)其中一個RequestManagerFragment生命周期方法走了,怎么知道哪些RequestManagerFragment綁定的LifeCycle應(yīng)該得到調(diào)用呢?理想的情況是,應(yīng)該讓綁定該RequestManagerFragment的Fragment所有的子Fragment的RequestManagerFragment的生命周期得到調(diào)用,比如如下場景中,Activity中各有兩個Fragment,兩個Fragment又各有兩個子Fragment,在所有Fragment中,均通過with(this)的方式來加載圖片,經(jīng)過之前的分析我們可以知道的是,ROOT RMF 中會保存有6個RMF(RMF即RequestManagerFragment):


11462765-2eec9cc331dad213.webp.jpg

當(dāng)如果F1 RMF生命周期做出反應(yīng)時,因為RequestManagerFragment是無界面的,所以可以理解為F1的生命周期做出反應(yīng)。我們希望F11和F12所綁定的RequestManagerFragment也要立即做出反應(yīng)。但是F2以及其底下的RequestManagerFragment則不應(yīng)響應(yīng)對應(yīng)生命周期事件,我們知道任何一個RequestManagerFragment可以通過rootRequestManagerFragment拿到這6個RMF,繼而拿到其所對應(yīng)的RequestManager,那么怎么去確定F11 RMF 和 F12 RMF呢?這就是RequestManagerTreeNode干的事情了,RequestManagerFragment中的非靜態(tài)內(nèi)部類FragmentRequestManagerTreeNode實現(xiàn)了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;
    }
}

這個類做的事情比較簡單,調(diào)用外部類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);
    }
}

RequestManager

RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
    //獲取RequestManagerFragment,并獲取綁定到這個fragment的RequestManager
    RequestManagerFragment current = getRequestManagerFragment(fm);
    RequestManager requestManager = current.getRequestManager();
    if (requestManager == null) {
    //如果獲取RequestManagerFragment還沒有綁定過RequestManager,那么就創(chuàng)建RequestManager并綁定到RequestManagerFragment
        requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
        current.setRequestManager(requestManager);
    }
    return requestManager;
}

RequestManager是一個非常核心的類,并且還實現(xiàn)了LifecycleListener來處理請求的生命周期。上述代碼在創(chuàng)建RequestManager時,傳遞了3個參數(shù),分別是context,前面分析過的初始化RequestManagerFragment所創(chuàng)建的LifeCycle和RequestManagerTreeNode。直接看RequestManager的構(gòu)造函數(shù):

public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
    this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
}

調(diào)用的另一個構(gòu)造方法,并增加了兩個新的參數(shù)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的暫停取消執(zhí)行操作都由RequestTracker來完成,如RequestManager暫停請求的實現(xiàn):

public void pauseRequests() {
    Util.assertMainThread();
    requestTracker.pauseRequests();
}

生命周期回調(diào)總結(jié)

在RequestManager構(gòu)造方法中,還會將自身添加到LifeCycle中,這樣,整個流程就暢通了

11462765-d93ece38acdbfb2a.webp.jpg

1.調(diào)用時通過Glide.with傳入context,利用context構(gòu)建一個Fragment
2.監(jiān)聽Fragment生命周期,銷毀時釋放Glide資源

Glide源碼分析流程圖

Glide加載原理.jpg

項目代碼:
https://github.com/games2sven/Glide

本文轉(zhuǎn)自作者“十年開發(fā)程序員”的Glide生命周期管理,如有侵權(quán),請聯(lián)系作者效效進(jìn)行修改。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容