〔兩行哥〕提綱挈領(lǐng),帶你梳理Glide主要源碼邏輯(一)

Glide的簡介就不多說了,只要記住這是Google推薦AndroidDev使用的圖片開源框架就好了。直接進(jìn)入正題,看看Glide的設(shè)計(jì)到底有何精妙之處,為何獲得了Google的青睞?

一個(gè)最簡單的Glide圖片加載邏輯舉例:

Glide.with(context).load(url).into(imageView);

我們的分析會(huì)以Glide3.8.0版本為例,基于此行代碼展開,分別分析with()、load()、into()三個(gè)方法內(nèi)部的邏輯。

一、基礎(chǔ)概念

Glide中涉及幾個(gè)概念,為便于理解,先粗略解釋:

1.Model

指的是對(duì)圖片源的封裝。在AndroidDev中,比較常見的就是網(wǎng)絡(luò)圖片地址、本地文件或資源ID。比如,String url = "https://www.baidu.com/img/bd_logo1.png",這里的url經(jīng)過Glide內(nèi)部的封裝后,就可以理解為一個(gè)Model。

2.Data

指的是對(duì)Model處理后的數(shù)據(jù)源的封裝,通常是InputStream。而在Glide中,將Model處理為Data的類便是ModelLoader。比如,通過上文的"https://www.baidu.com/img/bd_logo1.png"而取得的圖片輸入流,就可以理解為Data。

3.Resource

拿到圖片的輸入流可以直接展示在UI上嗎?顯然不可以。在第2點(diǎn)中我們提及了Data,即輸入流,如果要將其展示就需要對(duì)Data進(jìn)行解碼,解碼后的數(shù)據(jù)就是Resource。比如,上文的圖片輸入流經(jīng)過解碼后成為一個(gè)Bitmap對(duì)象或Drawable對(duì)象,這個(gè)對(duì)象就可以理解為Resource。而擔(dān)任解碼任務(wù)的角色,被成為ResourceDecoder(資源解碼器)。

4.TransformedResource&TranscodedResource

有時(shí)候我們獲取到的Resource并不適合展示,而是需要經(jīng)過處理才能展示,比如需要裁剪變換等(如調(diào)用centerCrop()、fitCenter()),那么經(jīng)過如此變換后的Rescourse稱為TransformedResource。
我們知道Glide是可以展示靜態(tài)圖,也可以展示動(dòng)態(tài)圖(動(dòng)態(tài)Gif),而解碼后的靜態(tài)圖片和動(dòng)態(tài)圖片(例如drawable和gif-drawable)類型是不同的, 為了統(tǒng)一處理邏輯,Glide內(nèi)部將這兩種類型的對(duì)象再次封裝為統(tǒng)一的GlideBitmapDrawable,這里的GlideBitmapDrawable就可以理解為TranscodedResource。

5.Target

這個(gè)比較容易理解,即需要在哪個(gè)目標(biāo)上進(jìn)行展示,比如ImageView。而Glide內(nèi)部將ImageView再次進(jìn)行了封裝,封裝后對(duì)象就可以理解為Target。

綜上所述,一個(gè)完整的圖片處理及展示流程如下:


圖1 Glide流程圖

二、基本用法

直接看代碼和注釋:

Glide.with(context)
        .load(url)
        .placeholder(R.mipmap.ic_launcher)//圖片加載前的占位圖
        .error(R.mipmap.ic_launcher)//圖片加載錯(cuò)誤的占位圖
        .fitCenter()
        .centerCrop()
        .override(500, 500)//調(diào)整圖片大小
        .skipMemoryCache(true)//跳過內(nèi)存緩存
        .crossFade(1000)//漸變顯示時(shí)間
        .diskCacheStrategy(DiskCacheStrategy.RESULT)//緩存處理后的圖像(如尺寸調(diào)整、裁剪后的圖像)
        .diskCacheStrategy(DiskCacheStrategy.SOURCE)//緩存原尺寸的圖像
        .diskCacheStrategy(DiskCacheStrategy.ALL)//緩存所有圖像
        .diskCacheStrategy(DiskCacheStrategy.NONE)//跳過磁盤緩存
        .priority(Priority.HIGH)//指定優(yōu)先級(jí)
        .into(imageView);

三、with()源碼邏輯

跟進(jìn)Glide類中尋找with()方法,發(fā)現(xiàn)with()方法有多種重載,包括with(Context context)、with(Activity activity)、with(Fragment fragment)等等。Glide之所以設(shè)計(jì)如此之多的with()方法重載,其目的在于將圖片的加載與傳入的Context組件或Fragment的生命周期相關(guān)聯(lián)。比如,當(dāng)用戶關(guān)閉當(dāng)前Activity,那么即使該Activity有正在進(jìn)行中的圖片網(wǎng)絡(luò)請(qǐng)求,Glide也會(huì)隨之取消該網(wǎng)絡(luò)請(qǐng)求。如果傳入的是ApplicationContext,那么網(wǎng)絡(luò)請(qǐng)求會(huì)持續(xù)進(jìn)行,直至App進(jìn)程被銷毀。
這里以with(Context context)為例看一下源碼實(shí)現(xiàn),其他重載方法邏輯基本一致:

Glide.java
    public static RequestManager with(Context  context) {
        RequestManagerRetriever retriever = RequestManagerRetriever.get();
        return retriever.get(activity);
    }

RequestManager類是Glide中用來處理圖片加載請(qǐng)求的管理類。RequestManagerRetriever類是用來創(chuàng)建和管理RequestManager對(duì)象的,其get()方法獲取了RequestManagerRetriever實(shí)例。繼續(xù)追蹤源碼,查看RequestManagerRetriever類中g(shù)et()方法的邏輯。

RequestManagerRetriever.java
    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) {
                return get((FragmentActivity) context);
            } else if (context instanceof Activity) {
                return get((Activity) context);
            } else if (context instanceof ContextWrapper) {
                return get(((ContextWrapper) context).getBaseContext());
            }
        }

        return getApplicationManager(context);
    }

在get()方法中,對(duì)Context的類型進(jìn)行了區(qū)分,有多種重載。我們主要分析一下Application和Activity類型的方法參數(shù),其他類型的參數(shù)讀者可以自行追蹤源碼。

RequestManagerRetriever.java
    private RequestManager getApplicationManager(Context context) {
        if (applicationManager == null) {
            synchronized (this) {
                if (applicationManager == null) {
                    applicationManager = new RequestManager(context.getApplicationContext(),
                            new ApplicationLifecycle(), new EmptyRequestManagerTreeNode());
                }
            }
        }
        return applicationManager;
    }

上述get(Application context)的方法中采取了雙重鎖單例模式獲取了一個(gè)RequestManager對(duì)象??梢园l(fā)現(xiàn),Glide在RequestManager的構(gòu)造方法中傳入了ApplicationLifecycle的實(shí)例,其作用是將RequestManager與Application生命周期綁定。

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    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);
        }
    }

上述get(Activity context)的方法中,首先進(jìn)行了線程判斷,如果在非主線程的情況下,返回了get(Application context)類型的RequestManager,而在主線程的情況下,通過該Activity context獲取到了相關(guān)聯(lián)的FragmentManager。這是Glide設(shè)計(jì)精妙之處之一,為什么要獲取FragmentManger呢?繼續(xù)追蹤源碼到fragmentGet(activity,fm)中。

RequestManagerRetriever.java
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    RequestManager fragmentGet(Context context, android.app.FragmentManager fm) {
        RequestManagerFragment current = getRequestManagerFragment(fm);
        RequestManager requestManager = current.getRequestManager();
        if (requestManager == null) {
            requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
            current.setRequestManager(requestManager);
        }
        return requestManager;
    }

分析一下fragmentGet()的邏輯。首先,方法第一行g(shù)etRequestManagerFragment()返回了RequestManagerFragment的實(shí)例current。RequestManagerFragment是啥?其實(shí)這是Glide封裝的Fragment,這里當(dāng)作Fragment來理解。先來截取部分RequestManagerFragment類的代碼:

RequestManagerFragment.java
public class RequestManagerFragment extends Fragment {

    ......
    private final ActivityFragmentLifecycle lifecycle;
    private RequestManager requestManager;

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

    /**
     * Sets the current {@link com.bumptech.glide.RequestManager}.
     *
     * @param requestManager The request manager to use.
     */
    public void setRequestManager(RequestManager requestManager) {
        this.requestManager = requestManager;
    }

    ActivityFragmentLifecycle getLifecycle() {
        return lifecycle;
    }

    /**
     * Returns the current {@link com.bumptech.glide.RequestManager} or null if none exists.
     */
    public RequestManager getRequestManager() {
        return requestManager;
    }

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

    @Override
    public void onStop() {
        super.onStop();
        lifecycle.onStop();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        lifecycle.onDestroy();
    }

}

對(duì)RequestManagerFragment劃重點(diǎn):
1.含有一個(gè)RequestManager類型的成員變量requestManager,通過getRequestManager()返回,通過setRequestManager()賦值。

即每個(gè)RequestManagerFragment對(duì)象都與一個(gè)RequestManager對(duì)象綁定。

2.含有一個(gè)ActivityFragmentLifecycle類型的成員變量lifecycle。通過對(duì)lifecycle實(shí)現(xiàn)的LifecycleListener接口回調(diào)來監(jiān)聽其生命周期,可以發(fā)現(xiàn)在RequestManagerFragment類的onStart()、onStop()、onDestroy()方法中對(duì)其進(jìn)行了調(diào)用。

即lifecycle對(duì)象實(shí)現(xiàn)了對(duì)RequestManagerFragment實(shí)例的生命周期監(jiān)聽。

回到fragmentGet()方法中,調(diào)用RequestManagerFragment中的getRequestManager()方法返回與其綁定的RequestManager對(duì)象(成員變量),如果為null(沒有與其綁定的RequestManager對(duì)象),則創(chuàng)建一個(gè)RequestManager對(duì)象,并調(diào)用setRequestManager()將其與RequestManagerFragment綁定。至此實(shí)現(xiàn)了RequestManagerFragment對(duì)象與RequestManager對(duì)象的一一綁定。
現(xiàn)在思考一個(gè)問題,Glide如何監(jiān)聽目標(biāo)Activity或Fragment的生命周期?上文已經(jīng)說明,根據(jù)傳入Glide的Context不同,Glide會(huì)監(jiān)聽其生命周期,根據(jù)生命周期管理圖片的網(wǎng)絡(luò)請(qǐng)求。
Glide直接監(jiān)聽Activity并不方便。那么在這里,Glide采用了另外的方法:
1.在Activity或Fragment的上層添再加一個(gè)Fragment,也就是上文一直在分析的RequestManagerFragment。這個(gè)Fragment并沒有覆寫createFragmentView(),即這是一個(gè)無UI的Fragment,當(dāng)添加了該Fragment,用戶是無法感知到的。
2.我們知道依附于Activity的Fragment有與被依附的Activity相關(guān)聯(lián)的生命周期,監(jiān)聽Fragment的生命周期也就是獲取到了被依附的Activity的生命周期。上文已經(jīng)劃過重點(diǎn):RequestManagerFragment通過接口回調(diào)的方式,在onStart()、onStop()、onDestroy()中調(diào)用了ActivityFragmentLifecycle的相應(yīng)生命周期方法,實(shí)現(xiàn)了對(duì)其生命周期的監(jiān)聽。
3.如果傳入Glide.with()參數(shù)為Fragment,那么處理邏輯同上。大家應(yīng)該也在Fragment中添加過Fragment吧?Glide同樣監(jiān)聽了RequestManagerFragment的生命周期。
4.每個(gè)RequestManagerFragment對(duì)象又與RequestManager對(duì)象一一綁定。至此,所有疑問解開:

Glide的每個(gè)RequestManager想要監(jiān)聽目標(biāo)Activity或Fragment生命周期用于執(zhí)行相關(guān)操作:
---> 每個(gè)RequestManager關(guān)聯(lián)著唯一的RequestManagerFragment
---> 該RequestManagerFragment是無UI的,被添加在目標(biāo)Activity或Fragment上, 而RequestManagerFragment的生命周期又與目標(biāo)Activity或Fragment相關(guān)聯(lián)
---> RequestManagerFragment通過接口回調(diào)的方式,在onStart()、onStop()、onDestroy()中調(diào)用了ActivityFragmentLifecycle的相應(yīng)生命周期方法,實(shí)現(xiàn)了生命周期的監(jiān)聽
綜上,RequestManager通過監(jiān)聽RequestManagerFragment這個(gè)不可見的Fragment的生命周期,間接監(jiān)聽了目標(biāo)Activity或Fragment。

這次的Glide源碼分析就到這里,主要分析了Glide內(nèi)部的處理流程以及with()方法中所做的操作,建議自行參閱相關(guān)源碼的同時(shí)閱讀本文。下一篇我們將繼續(xù)分析Glide的load()方法,再會(huì)。

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

相關(guān)閱讀更多精彩內(nèi)容

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