開始本文之前烤咧,DecodeJob它實現(xiàn)了Runnable接口偏陪,敏感的朋友可能已經(jīng)意識到,加載代碼的入口就在這里煮嫌,會在一個新的線程中去加載資源笛谦。DecodeJob這個類的代碼非常多,主要有以下幾個重要的點昌阿。
封裝一些從上面?zhèn)鬟^來的參數(shù)信息饥脑,不知道是否還有印象,我們的glide大部分信息是通過前面RequestBuilder中得到的懦冰。這里灶轰,它內(nèi)部構(gòu)造了一個DecodeHelper類,封裝了大部分的請求信息刷钢。
數(shù)據(jù)加載模塊DataFetcher與ModelLoader笋颤,以及加載數(shù)據(jù)的回調(diào)接口。詳細(xì)參考數(shù)據(jù)加載DataFetcher與ModelLoader結(jié)構(gòu)内地。DataFetcher中定義了加載數(shù)據(jù)的接口伴澄,其子類很多,比如從網(wǎng)絡(luò)加載或者是文件加載阱缓,均是由其子類具體實現(xiàn)非凌。
DataFetcherGenerator使用已注冊的{@link com.bumptech.glide.load.model.ModelLoader ModelLoaders}和一個模型生成一系列{@link com.bumptech.glide.load.data.DataFetcher DataFetchers}。在DataFetcherGenerator中茬祷,通過DecodeHelper類清焕,我們還可以拿到ModelLoader的信息,而通過ModelLoader我們可以得到LoadData的數(shù)據(jù)結(jié)構(gòu)祭犯,從而取得對應(yīng)的DataFetcher秸妥,進(jìn)而去獲取數(shù)據(jù)。DataFetcherGenerator結(jié)構(gòu)沃粗。
DecodeJob其他詳細(xì)信息可以參考DecodeJob結(jié)構(gòu)粥惧。
加載一個資源最終到一個ImageView上面的大致流程圖如下:
- SingleRequest的onSizeReady方法啟動Engine的load方法,同時將ResourceCallback傳入最盅。這個ResourceCallback最終會調(diào)用相關(guān)的Target突雪,完成資源的最終渲染。
- Engine的load方法,它里面會根據(jù)條件判斷涡贱,這里我們討論是本地完全沒有緩存的情況咏删,這個時候,load中问词,會創(chuàng)建EngineJob與DecodeJob督函,DecodeJob是真正開啟線程加載數(shù)據(jù)的地方,EngineJob負(fù)責(zé)調(diào)度DecodeJob以及和上層模塊通信,它們是一個一對一的關(guān)系辰狡。EngineJob中實現(xiàn)了DecodeJob.Callback用于監(jiān)聽下面數(shù)據(jù)加載的狀態(tài)锋叨,同時在EngineJon中維護(hù)了一系列的從Engine#load方法中傳入的ResourceCallback信息,用戶在監(jiān)聽到數(shù)據(jù)加載結(jié)果之后宛篇,通知上層模塊娃磺,也就是SingleRequest。隨之觸發(fā)啟動DecodeJob叫倍,開始任務(wù)偷卧。
- DecodeJob的run方法得到執(zhí)行,在run方法里段标,它會構(gòu)造一個DataFetcherGenerator,run方法里面會觸發(fā)DataFetcherGenerator的startNext方法涯冠,同時通過設(shè)置到DataFetcherGenerator的FetcherReadyCallback接口,監(jiān)聽數(shù)據(jù)的獲取狀態(tài)逼庞,再將結(jié)果上報至EngineJob中(它實現(xiàn)了DecodeJob.Callback接口)蛇更。
- DataFetcherGenerator的startNext,generator會從DecodeHelper中去獲取當(dāng)前的ModelLoader信息,構(gòu)造出一個LoadData結(jié)構(gòu)類型的數(shù)據(jù)赛糟,得到相應(yīng)的DataFetcher對象派任。DataFetcherGenerator子類實現(xiàn)了DataFetcher.DataCallback接口。它是用于監(jiān)聽DataFetcher#loadData結(jié)果璧南。
- DataFetcher#loadData完成之后掌逛,會將執(zhí)行結(jié)果上報至
DataFetcherGenerator,因為其實現(xiàn)了DataFetcher.DataCallback接口司倚,在其實現(xiàn)上面豆混,回繼續(xù)回調(diào)其成員變量執(zhí)行的FetcherReadyCallback中的方法,而此時动知,F(xiàn)etcherReadyCallback實現(xiàn)類正是DecodeJob皿伺,因此,代碼繼續(xù)執(zhí)行到DecodeJob的回調(diào)方法中盒粮,我們先至考慮簡單的情況鸵鸥,忽略線程之間的切換。 - 回到DecodeJob的FetcherReadyCallback的實現(xiàn)中丹皱,它接下來會繼續(xù)回調(diào)設(shè)置在其成員變量的類型為DecodeJob.Callback引用妒穴,而正是EngineJob實現(xiàn)了這個Callback,因此,代碼流程進(jìn)一步轉(zhuǎn)換給到EngineJob中摊崭。
- EngineJob實現(xiàn)了DecodeJob.Callback讼油,此時還沒有做線程切換,是處于和DecodeJob#run方法相同的線程呢簸,此時汁讼,EngineJob中利用Handler機制淆攻,將繼續(xù)分發(fā)加載到的數(shù)據(jù)的結(jié)果,觸發(fā)其handleResultOnMainThread方法嘿架。見名思義,此時已經(jīng)切換到了主線程啸箫。
- EngineJob#handleResultOnMainThread方法中耸彪,會回調(diào)在上面講到的,它中維護(hù)了一系列的從Engine#load方法中傳入的ResourceCallback信息忘苛,所以這里會對它們繼續(xù)進(jìn)行回調(diào)蝉娜。
- ResourceCallback,它的實現(xiàn)是在SingleRequest中扎唾,在它的實現(xiàn)中召川,會將結(jié)果交給相應(yīng)的Target去處理,而我們的ImageView渲染資源正是由這些Target在調(diào)度胸遇。所以荧呐,最終資源就成功的顯示到了控件上面。
總體來說纸镊,宏觀上代碼邏輯還是很清晰的倍阐,一次加載過程,會創(chuàng)建一個SingleRequest逗威,調(diào)用全局的加載引擎Engine峰搪,去創(chuàng)建一對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引用通知到對應(yīng)的控件,完成資源的渲染差凹。同時EngineJob也會告知Engine期奔,此次job已經(jīng)加載完成,是由EngineJobListener完成的危尿。大致就是一個鏈?zhǔn)降腃allback回調(diào)過程呐萌。后面我會在代碼上,根據(jù)這個大綱谊娇,詳細(xì)分析一次從網(wǎng)絡(luò)加載肺孤,并緩存到磁盤的詳細(xì)過程。