讀glide 源碼

glide是android上實(shí)現(xiàn)圖片加載的庫中很常用的一個(gè),趁著有時(shí)間,也了解下其源碼,我看的是v4版本,因?yàn)橹耙呀?jīng)看過v4版本新特性的介紹,所以就直接閱讀這個(gè)版本源碼,不熟悉的讀者可以先看一下特性介紹。

開始

從github上面clone完項(xiàng)目之后,用android studio打開,目錄很多,搜索了一下,在library目錄下是核心功能代碼,我們還是通過示例代碼開始:
···
Glide.with(fragment)
.load(myUrl)
.into(imageView);
···
這應(yīng)該是最簡(jiǎn)單的使用,那么我們就就Glide類開始,先找到with方法。with方法有不同參數(shù)的重載方法,我們看一下with(Context)方法,顯示調(diào)用getRetriever獲取RequestManagerRetriever實(shí)例,這個(gè)方法里,先是調(diào)用Glide.get(context)獲取Glide的實(shí)例,Glide是單例的,因?yàn)関4版本使用了注解處理器來生成AppModule的實(shí)現(xiàn)類,所以這里會(huì)有反射獲取實(shí)例,然后通過GlideBuilder構(gòu)造Glide實(shí)例,內(nèi)部實(shí)現(xiàn)就是初始化Glide里的內(nèi)部域,這里我們會(huì)看到Engine(負(fù)責(zé)加載及管理資源),BitmapPool,MemoryCache,RequestManagerRetriever等類,注意在Glide的構(gòu)造方法里,會(huì)構(gòu)造Registry實(shí)例,然后調(diào)用方法將loading,encoding,decoding的邏輯實(shí)現(xiàn)類加到Registry內(nèi)部域中,最后構(gòu)造GlideContext實(shí)例,這個(gè)類后面很多地方都用到。得到Glide實(shí)例后,調(diào)用getRequestManagerRetriever得到RequestManagerRetriever的實(shí)例,然后調(diào)用其實(shí)例方法得到RequestManager實(shí)例,這里會(huì)用到RequestManagerFactory的build方法構(gòu)造,而這個(gè)RequestManagerFactory只是個(gè)接口,如果我們沒有配置,會(huì)使用默認(rèn)實(shí)現(xiàn),build方法實(shí)現(xiàn)就是調(diào)用RequestManage的構(gòu)造方法來構(gòu)造,構(gòu)造方法會(huì)使用到一些參數(shù),包括Glide實(shí)例,Lifecycle接口實(shí)現(xiàn),Context實(shí)例等,至此with方法結(jié)束。

接著我們看一下RequetManager的load方法,它有很多重載方法,接收不同類型的參數(shù),我們這里看一下參數(shù)類型是String的方法,這個(gè)方法首先調(diào)用asDrawable得到RequestBuilder<Drawable>實(shí)例,然后調(diào)用其實(shí)例方法load(String),我們先來看asDrawable方法,這個(gè)方法最終就是調(diào)用new RequestBuilder<>(glide, this, resourceClass, context)構(gòu)造RequestBuilder實(shí)例,這里resourceClass類型是Class<Drawable>。然后我們就來看一下RequestBuilder類的load(String)方法,其實(shí)現(xiàn)最終會(huì)將String參數(shù)賦值給其內(nèi)部域model,然后設(shè)置isModelSet為true,然后就返回這個(gè)RequestBuilder了。

看來加載圖片的關(guān)鍵代碼在into(ImageView)中了,讓我們來看一下RequestBuilder的into方法。into(ImageView)方法會(huì)先判斷條件,是否需要將ImageView的ScaleType設(shè)置也添加到當(dāng)前RequestBuilder配置中(因?yàn)镽equestBuilder繼承BaseRequestOptions),然后調(diào)用into的重載方法:
into(@NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options, Executor callbackExecutor)。我們看一下這個(gè)方法,這里先是調(diào)用buildRequest方法,其實(shí)現(xiàn)就是調(diào)用buildRequestRecursive方法,我們接著看其實(shí)現(xiàn),先是初始化parentCoordinator,然后調(diào)用buildThumbnailRequestRecursive方法,其實(shí)現(xiàn)里分為三種情況,如果thumbnailBuilder內(nèi)部域不為null,那么會(huì)做一些參數(shù)處理,然后創(chuàng)建一個(gè)ThumbnailRequestCoordinator實(shí)例,其是Request接口的實(shí)現(xiàn)類,職責(zé)是內(nèi)部維護(hù)thumbail縮略圖的加載和full image原圖的加載,這里調(diào)用SingleRequest.obtain獲取原圖的request,遞歸調(diào)用thumbnailBuilder.buildRequestRecursive獲取thumbail縮略圖的request,將兩者賦值給ThumbnailRequestCoordinator之后返回這個(gè)實(shí)例;如果thumbSizeMultiplier不為null,那么這里也要?jiǎng)?chuàng)建ThumbnailRequestCoordinator實(shí)例,只是縮略圖和原圖的request都是通過SingleRequest.obtain生成的;如果都不是以上兩者情況,則通過SingleRequest.obtain獲取原圖的request,這里也就是說不加載縮略圖、

得到了Request(或者是ThumbnailRequestCoordinator,或者是SingleRequest),我們調(diào)用target.getRequest,這里會(huì)獲取imageview的之前的request(如果有的話),比較這兩個(gè)request是否相等,如果相等,那么會(huì)根據(jù)其他條件做處理,如果不相等,會(huì)調(diào)用以下代碼:
···
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
···
第一步先取消target上之前的request并釋放資源,然后設(shè)置新的request,然后track方法,內(nèi)部會(huì)調(diào)用以下代碼:
···
targetTracker.track(target);
requestTracker.runRequest(request);
···
第一步是把這個(gè)target加到target內(nèi)部維護(hù)的列表,TargetTracker會(huì)賦值在activity或fragment生命周期變化時(shí)回調(diào)target對(duì)應(yīng)onStart,onStop,onDestroy方法。而runRequest方法,先是把這個(gè)request加到RequestTracker內(nèi)部列表中以便在生命周期變化時(shí)管理所有request,然后如果isPaused內(nèi)部域?yàn)閒alse,說明沒有暫停所有請(qǐng)求,則調(diào)用request的begin方法開始加載,否則調(diào)用request的clear方法并把這個(gè)request加到pendingRequests中,以便條件滿足時(shí)重啟request。

剛提到TargetTracker可以在生命周期變化時(shí)進(jìn)行處理,那它又是如何得知生命周期變化的呢,其實(shí)在with(Activity)方法中,會(huì)將一個(gè)沒有view的fragment加到activity的fragment manager,這樣就可以監(jiān)聽生命周期變化。

回過頭來我們來看一下request的begin方法,之前提到Request的兩個(gè)實(shí)現(xiàn)類,ThumbnailRequestCoordinator和SingleRequest,在ThumbnailRequestCoordinator內(nèi)部的begin方法,基本就是順序調(diào)用origin原圖和thumbnail縮略圖這個(gè)兩個(gè)SingleRequest的begin方法,那我們來看一下SingleRequest的begin方法。

首先是參數(shù)驗(yàn)證和request加載狀態(tài)驗(yàn)證,如果已經(jīng)加載完成,則直接使用緩存資源調(diào)用onResoureReady;如果已經(jīng)開始,則會(huì)拋出異常;如果是其他情況,都視為可以重新啟動(dòng)加載,然后這里會(huì)調(diào)用Engine的load方法,這個(gè)Engine之前在Glide初始化的時(shí)候有提到,這里就深入了解。

Engine實(shí)例的構(gòu)造方法內(nèi)部,會(huì)創(chuàng)建多個(gè)GlideExecutor(這個(gè)類擴(kuò)展ExecutorService),有緩存存在情況下的GlideExecutor(有1個(gè)線程),有緩存不存在情況下的GlideExecutor(兩個(gè)實(shí)例,一個(gè)實(shí)例內(nèi)部線程數(shù)根據(jù)硬件cpu核心數(shù)來定,最多不超過4個(gè),還有一個(gè)實(shí)例內(nèi)部線程數(shù)不限制),還有負(fù)責(zé)動(dòng)畫的GlideExecutor(1或2個(gè)線程,gif圖需要用到)

然后我們來看一下Engine的load方法,首先是構(gòu)造一個(gè)EngineKey實(shí)例,這是Key接口的實(shí)現(xiàn),用作內(nèi)存中緩存的key,然后這里按照以下步驟執(zhí)行:
1)首先檢查當(dāng)前activeResource活躍資源(指被至少一個(gè)request使用并且還沒釋放的資源)的集合中是否存在key對(duì)應(yīng)的EngineResource,如果存在則調(diào)用onResourceReady并結(jié)束,否則繼續(xù)
2)檢查memoryCache緩存中是否存在key對(duì)應(yīng)的EngineResource,如果存在也是調(diào)用onResourceReady并結(jié)束,否則繼續(xù)
3)檢查正在執(zhí)行加載任務(wù)的集合中是否存在key對(duì)應(yīng)的EngineJob,存在的話就將調(diào)用EngineJob的addCallback方法將當(dāng)前需要執(zhí)行任務(wù)的callback添加進(jìn)去,以便任務(wù)完成時(shí)收到回調(diào);否則的話繼續(xù)
4)創(chuàng)建一個(gè)EngineJob,將當(dāng)前需要執(zhí)行任務(wù)的callback添加進(jìn)去并開始執(zhí)行加載

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。