開始本文之前,DecodeJob它實(shí)現(xiàn)了Runnable接口,敏感的朋友可能已經(jīng)意識(shí)到,加載代碼的入口就在這里,會(huì)在一個(gè)新的線程中去加載資源。DecodeJob這個(gè)類的代碼非常多,主要有以下幾個(gè)重要的點(diǎn)。
封裝一些從上面?zhèn)鬟^(guò)來(lái)的參數(shù)信息,不知道是否還有印象,我們的glide大部分信息是通過(guò)前面RequestBuilder中得到的。這里,它內(nèi)部構(gòu)造了一個(gè)DecodeHelper類,封裝了大部分的請(qǐng)求信息。
數(shù)據(jù)加載模塊DataFetcher與ModelLoader,以及加載數(shù)據(jù)的回調(diào)接口。詳細(xì)參考數(shù)據(jù)加載DataFetcher與ModelLoader結(jié)構(gòu)。DataFetcher中定義了加載數(shù)據(jù)的接口,其子類很多,比如從網(wǎng)絡(luò)加載或者是文件加載,均是由其子類具體實(shí)現(xiàn)。
DataFetcherGenerator使用已注冊(cè)的{@link com.bumptech.glide.load.model.ModelLoader ModelLoaders}和一個(gè)模型生成一系列{@link com.bumptech.glide.load.data.DataFetcher DataFetchers}。在DataFetcherGenerator中,通過(guò)DecodeHelper類,我們還可以拿到ModelLoader的信息,而通過(guò)ModelLoader我們可以得到LoadData的數(shù)據(jù)結(jié)構(gòu),從而取得對(duì)應(yīng)的DataFetcher,進(jìn)而去獲取數(shù)據(jù)。DataFetcherGenerator結(jié)構(gòu)。
DecodeJob其他詳細(xì)信息可以參考DecodeJob結(jié)構(gòu)。
加載一個(gè)資源最終到一個(gè)ImageView上面的大致流程圖如下:
sequence_engine.png
- SingleRequest的onSizeReady方法啟動(dòng)Engine的load方法,同時(shí)將ResourceCallback傳入。這個(gè)ResourceCallback最終會(huì)調(diào)用相關(guān)的Target,完成資源的最終渲染。
- Engine的load方法,它里面會(huì)根據(jù)條件判斷,這里我們討論是本地完全沒(méi)有緩存的情況,這個(gè)時(shí)候,load中,會(huì)創(chuàng)建EngineJob與DecodeJob,DecodeJob是真正開啟線程加載數(shù)據(jù)的地方,EngineJob負(fù)責(zé)調(diào)度DecodeJob以及和上層模塊通信,它們是一個(gè)一對(duì)一的關(guān)系。EngineJob中實(shí)現(xiàn)了DecodeJob.Callback用于監(jiān)聽下面數(shù)據(jù)加載的狀態(tài),同時(shí)在EngineJon中維護(hù)了一系列的從Engine#load方法中傳入的ResourceCallback信息,用戶在監(jiān)聽到數(shù)據(jù)加載結(jié)果之后,通知上層模塊,也就是SingleRequest。隨之觸發(fā)啟動(dòng)DecodeJob,開始任務(wù)。
- DecodeJob的run方法得到執(zhí)行,在run方法里,它會(huì)構(gòu)造一個(gè)DataFetcherGenerator,run方法里面會(huì)觸發(fā)DataFetcherGenerator的startNext方法,同時(shí)通過(guò)設(shè)置到DataFetcherGenerator的FetcherReadyCallback接口,監(jiān)聽數(shù)據(jù)的獲取狀態(tài),再將結(jié)果上報(bào)至EngineJob中(它實(shí)現(xiàn)了DecodeJob.Callback接口)。
- DataFetcherGenerator的startNext,generator會(huì)從DecodeHelper中去獲取當(dāng)前的ModelLoader信息,構(gòu)造出一個(gè)LoadData結(jié)構(gòu)類型的數(shù)據(jù),得到相應(yīng)的DataFetcher對(duì)象。DataFetcherGenerator子類實(shí)現(xiàn)了DataFetcher.DataCallback接口。它是用于監(jiān)聽DataFetcher#loadData結(jié)果。
- DataFetcher#loadData完成之后,會(huì)將執(zhí)行結(jié)果上報(bào)至
DataFetcherGenerator,因?yàn)槠鋵?shí)現(xiàn)了DataFetcher.DataCallback接口,在其實(shí)現(xiàn)上面,回繼續(xù)回調(diào)其成員變量執(zhí)行的FetcherReadyCallback中的方法,而此時(shí),F(xiàn)etcherReadyCallback實(shí)現(xiàn)類正是DecodeJob,因此,代碼繼續(xù)執(zhí)行到DecodeJob的回調(diào)方法中,我們先至考慮簡(jiǎn)單的情況,忽略線程之間的切換。 - 回到DecodeJob的FetcherReadyCallback的實(shí)現(xiàn)中,它接下來(lái)會(huì)繼續(xù)回調(diào)設(shè)置在其成員變量的類型為DecodeJob.Callback引用,而正是EngineJob實(shí)現(xiàn)了這個(gè)Callback,因此,代碼流程進(jìn)一步轉(zhuǎn)換給到EngineJob中。
- EngineJob實(shí)現(xiàn)了DecodeJob.Callback,此時(shí)還沒(méi)有做線程切換,是處于和DecodeJob#run方法相同的線程,此時(shí),EngineJob中利用Handler機(jī)制,將繼續(xù)分發(fā)加載到的數(shù)據(jù)的結(jié)果,觸發(fā)其handleResultOnMainThread方法。見名思義,此時(shí)已經(jīng)切換到了主線程。
- EngineJob#handleResultOnMainThread方法中,會(huì)回調(diào)在上面講到的,它中維護(hù)了一系列的從Engine#load方法中傳入的ResourceCallback信息,所以這里會(huì)對(duì)它們繼續(xù)進(jìn)行回調(diào)。
- ResourceCallback,它的實(shí)現(xiàn)是在SingleRequest中,在它的實(shí)現(xiàn)中,會(huì)將結(jié)果交給相應(yīng)的Target去處理,而我們的ImageView渲染資源正是由這些Target在調(diào)度。所以,最終資源就成功的顯示到了控件上面。
總體來(lái)說(shuō),宏觀上代碼邏輯還是很清晰的,一次加載過(guò)程,會(huì)創(chuàng)建一個(gè)SingleRequest,調(diào)用全局的加載引擎Engine,去創(chuàng)建一對(duì)EngineJob與DecodeJob,最后在DecodeJob中,根據(jù)DataFetcherGenerator獲取到相應(yīng)的DataFetcher,執(zhí)行數(shù)據(jù)的加載。成功之后,一步步回調(diào)回去。先是DataFetcher到DataFetcherGenerator,再是DataFetcherGenerator到DecodeJob,再是從DecodeJob到EngineJob,進(jìn)而在EngineJob中做線程切換,回到主線程,將結(jié)果回調(diào)至SingeRequest,再由SingleRequest中保存的Target引用通知到對(duì)應(yīng)的控件,完成資源的渲染。同時(shí)EngineJob也會(huì)告知Engine,此次job已經(jīng)加載完成,是由EngineJobListener完成的。大致就是一個(gè)鏈?zhǔn)降腃allback回調(diào)過(guò)程。后面我會(huì)在代碼上,根據(jù)這個(gè)大綱,詳細(xì)分析一次從網(wǎng)絡(luò)加載,并緩存到磁盤的詳細(xì)過(guò)程。