轉(zhuǎn)載請(qǐng)標(biāo)明地址 QuincySx: http://www.itdecent.cn/p/cf8f8f90f621
這篇文章是這個(gè)系列的第一篇文章,我第一次寫這樣連續(xù)系列的文章,我先一層一層的剝開 Glide ,如果誰有更好的想法歡迎提出。
需知:本篇沒有貼出太多 Glide 代碼來對(duì)照分析,只是一個(gè)最簡單的流程
看完這篇文章你會(huì)得到什么:
這篇文章你將會(huì)看到 Glide 的基本運(yùn)作流程
Glide 的基本用法 整篇文章都是按照此代碼環(huán)境來講解的
Glide.with(Activity).load(Url).into(ImageView);
各個(gè)流程對(duì)象的轉(zhuǎn)換
首先我先說一下 Glide 在各個(gè)流程上對(duì)象的轉(zhuǎn)換
首先調(diào)用 with() 方法 會(huì)返回 RequestManager 這個(gè)對(duì)象
然后調(diào)用 load() 此時(shí)會(huì)返回 DrawableTypeRequest 對(duì)象,但是這個(gè)地方要注意了 這個(gè)對(duì)象繼承自 GenericRequestBuilder 對(duì)象,從詞義上來看
這個(gè)對(duì)象是生成『通用請(qǐng)求生成器』,其實(shí)它的作用和他的詞義其實(shí)一樣的(不得不給 Glide 作者點(diǎn)個(gè)贊)然后調(diào)用 init() 方法會(huì)構(gòu)建 ViewTarget 然后開始獲取資源,緩存,讀取緩存,變換等處理然后放在 ImageView 上面
具體分析每個(gè)步驟所做的事情
具體分析每個(gè)以下每個(gè)步驟
with 方法
這個(gè)方法主要是往當(dāng)前 Activity 里面添加 Fragment 并注冊(cè)生命周期監(jiān)聽器,構(gòu)建 RequestManager 、如果 Glide 沒有初始化,也會(huì)初始化 Glide (RequestManager 這個(gè)地方要注意了,這個(gè)對(duì)象是一個(gè) Activity 會(huì)有一個(gè) RequestManager 對(duì)象,他不是單例的,為什么呢可以去看源碼)
with() 這個(gè)方法有好幾個(gè)重載、但是呢...不用管他、他無論傳成什么都是干的一個(gè)事我就隨便挑一個(gè)說了
with(FragmentActivity activity),在方法里面調(diào)用RequestManagerRetriever.get()會(huì)獲取 RequestManagerRetriever (這個(gè)類的作用是提供 RequestManager)的單例,然后調(diào)用RequestManagerRetriever.get()方法,獲取 FragmentActivity 中的 FragmentManager 對(duì)象(不同的方法可能獲取方法不同,這里我們直說這一種,其他的可以自己去看一下源碼),然后把 SupportRequestManagerFragment 加入到當(dāng)前的 Activity 中(添加這個(gè) Fragment 的目的是為了監(jiān)聽當(dāng)前 Activity 的生命周期、這里監(jiān)聽生命周期的作用是及時(shí)取消圖片資源獲取,轉(zhuǎn)換的任務(wù),以防止性能上的浪費(fèi)),然后把 Fragment 的監(jiān)聽器取出來,構(gòu)造出 RequestManager ,再把 RequestManager 放到 Fragment 里面(后面幾個(gè)方法我沒有提名字,只提了實(shí)現(xiàn)了什么,你們看一下源碼就會(huì)懂)構(gòu)造 RequestManager 的時(shí)候會(huì)獲取單例的 Glide,如果 Glide 沒有初始化 他會(huì)通過 GlideBuilder 來構(gòu)建 Glide 里面完成了一些 緩存、線程池、轉(zhuǎn)換、資源獲取以及轉(zhuǎn)換的控制類 等等的東西,然后調(diào)用 new 出 Glide
在 Glide 的構(gòu)造方法里 注冊(cè)了一堆監(jiān)聽,以及類的提供者,注冊(cè)不同類型的
ModelLoader ,注冊(cè)變換的類等等(這個(gè)方法好多東西我還不知道是干什么的 我搞清了會(huì)更新博客)然后他就會(huì)讀取 Manifest 的里面 value 為 “ GlideModule” 的所有 meta-data 標(biāo)簽,然后獲取 key 通過反射的方式獲取 GlideModule,然后調(diào)用
GlideModule.registerComponents()方法,將 ModelLoader 注冊(cè)進(jìn) Glide 并且替換掉相同類型的 ModelLoader (為什么會(huì)講是會(huì)替換掉相同類型的 ModelLoader 呢,因?yàn)?load() 有好多重載,它是根據(jù)類型把不同類型的 ModelLoader 放到一個(gè) Map 里供,解析使用,具體到 into 再細(xì)說),通過這種方式我們就能夠在外部提供自己的解析器了ConnectivityMonitor 來判斷有沒有網(wǎng)絡(luò)狀態(tài)獲取的權(quán)限 然后選擇往 Fragment 的監(jiān)聽器里面放網(wǎng)絡(luò)監(jiān)聽器,還是空監(jiān)聽器,如果當(dāng)前 APP 有獲取網(wǎng)絡(luò)狀態(tài)的權(quán)限,他就會(huì)在網(wǎng)絡(luò)改變的時(shí)候,調(diào)用任務(wù)隊(duì)列,會(huì)重新啟動(dòng)任務(wù)
load 方法 此處分析的是傳入 String 參數(shù) 并且是個(gè) URL 地址
這個(gè)方法主要功能是根據(jù)傳入的參數(shù)類型返回相應(yīng)的 ModelLoader ,維護(hù)請(qǐng)求隊(duì)列、 Activity 生命周期監(jiān)聽器、等、并構(gòu)建 DrawableTypeRequest 對(duì)象
1. 在fromString() 中調(diào)用 RequestManager.loadGeneric(Class<T> modelClass) 方法來獲取 GenericRequestBuilder<T> 類,那么這個(gè)方法干了什么呢。
- 首先調(diào)用
Glide.buildStreamModelLoader()方法,然后在方法里調(diào)用buildModelLoader(modelClass, InputStream.class, context),再在方法里調(diào)用Glide.get(context).getLoaderFactory().buildModelLoader(modelClass, resourceClass)他會(huì)現(xiàn)在 Glide 中獲取 ModelLoader 的工廠(GenericLoaderFactory 這個(gè)類里面保存有 完整的 ModelLoader 列表,和緩存的 ModelLoader,這個(gè)類是在 Glide 的構(gòu)造方法中 new 出來的,跟隨 Glide 為單例),獲取之后調(diào)用工廠的buildModelLoader()的方法,在這個(gè)方法中他首先獲取 緩存的 ModelLoader 如果沒有就讀取整個(gè) ModelLoader 列表來獲取 ModelLoader,并且把這個(gè) ModelLoader 緩存起來,以后再用的時(shí)候就可以快速讀取 - 調(diào)用
Glide.buildFileDescriptorModelLoader(modelClass, context)方法,然后在這個(gè)方法里調(diào)用了buildModelLoader(modelClass, ParcelFileDescriptor.class, context)和上個(gè)步驟一樣的方法,并傳入了一個(gè)類型,具體就不多說了,流程一樣 - 第三步他會(huì)構(gòu)建出 new 出 DrawableTypeRequest 對(duì)象
2. loadGeneric() 調(diào)用完,回到 load 方法哪里他會(huì)調(diào)用 DrawableRequestBuilder 的 load(ModelType model) 方法,把泛型參數(shù)儲(chǔ)存一下,在我們的分析環(huán)境下就是 String 類型的,到此為止 DrawableTypeRequest 就構(gòu)建出來了,他是繼承自 DrawableRequestBuilder 也繼承自 GenericRequestBuilder,下一個(gè)步驟就密切和 這個(gè)類相關(guān)了
into 方法
這個(gè)方法比較重要
- 調(diào)用 into(ImageView view) 方法,他會(huì)先判斷圖片顯示方式然后設(shè)置不同的變換,然后先調(diào)用
buildImageViewTarge()方法,在方法里面再調(diào)用 ImageViewTargetFactory.buildTarget(Class<Z> clazz) 方法來生成 ViewTarget(ImageViewTargetFactory 類也是在 Glide 初始化的時(shí)候就生成了,在 buildTarget() 方法中的 clazz 參數(shù)是在 DrawableTypeRequest 的父類 DrawableRequestBuilder 中的構(gòu)造中傳入的是 GlideDrawable.class ),所以這個(gè) switch 語句 最終獲取的也是 GlideDrawableImageViewTarget 類,這個(gè)類的構(gòu)造也只是 存儲(chǔ)的一下 View 此時(shí)先不必深究 - ViewTarget 構(gòu)建完了然后調(diào)用
into(Y target)方法(Y extends Target<TranscodeType>),然后判斷當(dāng)前是否是主線程、如果不是那就要蹦沙卡拉卡了,然后在 TargetView 中獲取 Request 如果有則停止并移除,通過buildRequest()方法獲取 Request 然后添加到 ViewTarget 中,添加到 RequestTracker 隊(duì)列中,以及監(jiān)聽中,這一步的源碼我貼出來,看最下面 - 第三步將下面源碼片段的
buildRequest(target),這個(gè)方法里面有個(gè)判斷他的意思是,如果用戶沒有設(shè)定 Request 的線程優(yōu)先級(jí),就默認(rèn)(這個(gè)地方 Glide 的默認(rèn)線程優(yōu)先級(jí)是低于 UI 線程的,他就是怕影響 UI 線程,如果沒有特殊要求建議不要改動(dòng)),然后調(diào)用buildRequestRecursive()這個(gè)方法,這個(gè)方法首先判斷用戶是否設(shè)置過加載的資源是圖片的縮略圖(低配版的圖片),下面兩個(gè)判斷都是和縮略圖有關(guān)系,如果就按照咱們上下文環(huán)境,也就是最簡單的流程他走的是 else 調(diào)用obtainRequest()方法,在方法里再調(diào)用GenericRequest.obtain()來構(gòu)建 GenericRequest ,構(gòu)建的詳細(xì)過程就不說了大家自己看一下 - 第四步
RequestTracker.runRequest(request)從詞義上來看就是開始請(qǐng)求,實(shí)際呢,你只要知道這個(gè)方法是運(yùn)行 Request 就行了(這段代碼簡單,你簡單看一下就行,RequestTracker 的作用是暫停、開始、暫停或重新運(yùn)行任務(wù),他是和 Fragment 生命周期有關(guān)聯(lián)的),然后調(diào)用Request.begin()方法改變 Request 的 狀態(tài),然后調(diào)用onSizeReady()方法再次修改 Request 的狀態(tài),獲取各種加載器,調(diào)用Engine.load()(這個(gè)類以及方法的作用是控制緩存獲取資源等任務(wù),下一篇會(huì)詳細(xì)講),你會(huì)發(fā)現(xiàn) load 方法里面有個(gè)回調(diào)接口,他傳遞的是 this,他會(huì)繼續(xù)調(diào)用target.onLoadStarted(getPlaceholderDrawable());這個(gè)方法可以點(diǎn)進(jìn)去看一下功能,就是把占位的圖片加載到 View 上,我們?cè)俜祷厝タ?Engine.load()里面,他加載成功的時(shí)候會(huì)回調(diào)onResourceReady(Resource<?> resource)方法,因?yàn)槲覀兓卣{(diào)傳的是 this 所以回調(diào)了GenericRequest.onResourceReady()他會(huì)把資源加載到 ImageView 上去(這里是簡單說了一下流程,下一篇會(huì)詳說)
Request request = buildRequest(target);
target.setRequest(request);
lifecycle.addListener(target);
requestTracker.runRequest(request);
小結(jié)
我自己本身沒有讀過這種類型的庫,我都是看的 github 上面用到的庫,沒事簡單的看一看。說一下感想吧!我一開始想看 Glide 的時(shí)候有點(diǎn)怕,不知道如何下手也怕讀不明白,就下載了源碼去簡單的看一看。我讀的思路就是這個(gè)庫的入門用法Glide.with(Activity).load(Url).into(ImageView);最簡單的語句,就慢慢的一點(diǎn)點(diǎn)的看,看他是怎么轉(zhuǎn)換的每個(gè)步驟怎么走的,如果理不清楚可以依靠 Debug 調(diào)試,跟著他走一遍,我也是看了好幾遍才找到頭緒。堅(jiān)持才會(huì)贏嘛,網(wǎng)上都說他們讀了兩天就差不多了,咱比不了啊!看了四五天就稍微有個(gè)頭緒,慢慢看吧,堅(jiān)持就是勝利?。。?/p>
我的理解還是有點(diǎn)淺薄同時(shí)文章寫的也不熟練,歡迎各位提出問題