詳談高大上的圖片載入框架Glide -原始碼篇

Code4Android發表於2016-09-22

在上篇文章中,我們介紹了Glide圖片載入框架的使用,通過之前的學習,我們可能已經能熟練的將Glide圖片載入框架運用到我們的專案中,但是如果有人問你它是如何載入,工作原理是怎樣的?為什麼自定義GlideModule只需要在Manifest檔案中加入meta-data即可?等等很多載入流程以及使用的注意事項。當然要想搞明白這些問題,就需要我們對Glide原始碼有個大致的認識,去剖析原始碼深處的奧祕。

接下來就讓我們一起去進入Glide的原始碼世界,本篇文章分析的是Glide 3.7.0版本。特別提醒,閱讀本篇文章之前要對Glide的用法要先有一個瞭解,可以先閱讀上篇文章,詳談高大上的圖片載入框架Glide -應用篇

此篇文章是自己學習的一個記錄,若對閱讀文章的你有一定幫助,很是高興,當然文章如有不足或者錯誤的地方,歡迎指正,避免我給其他讀者錯誤引導

如果你閱讀過上篇文章,或者你使用過Glide,就知道Glide載入圖片的最簡單方式就是

那麼這篇文章就以這句簡單的程式碼為主線,逐步深入Glide的原始碼。

Glide.with(context)

Glide有四個靜態的過載方法with(),其內部都通過RequestManagerRetriever相應的get過載方法獲取一個RequestManager物件。RequestManagerRetriever提供各種過載方法的好處就是可以將Glide的載入請求與Activity/Fragment的生命週期繫結而自動執行請求,暫停操作。

接下來我們拿Activity引數分析Glide請求如何和繫結生命週期自動請求,暫停,以及銷燬。

assertNotDestroyed主要斷言Activity是否已經Destroyed。若是沒有銷燬,或者Activity的FragmentManager ,然後通過fragmentGet返回RequestManager。

最終通過getRequestManagerFragment()方法獲取一個RequestManagerFragment 物件。

此時我們看到RequestManagerFragment 繼承了Fragment.並且在其生命週期onStart(),onStop(),onDestory(),呼叫了ActivityFragmentLifecycle 相應的方法,ActivityFragmentLifecycle實現了Lifecycle 介面,在其中通過addListener(LifecycleListener listener)回撥相應(LifecycleListener的 onStart(),onStop(),onDestory())週期方法。LifecycleListener是監聽生命週期時間介面。
再次回到fragmentGet方法裡下面一句程式碼

對於RequestManager類,該類實現了LifecycleListener,如下程式碼

它將剛建立的fragment的lifeCycle傳入,並將RequestManager這個listener新增到lifeCycle中,從而實現繫結。在RequestManager的構造方法裡看到了requestTracker,該物件就是跟蹤請求取消,重啟,完成,失敗。RequestManagerFragment 主要是用來連線生命週期方法,RequestManager用來實現生命週期中請求方法,而RequestManagerRetriever繫結了RequestManager。

GlideModule實現

在構造方法中還初始化了通過Glide.get(context);初始化了Glide物件

通過get方法單例方式獲取例項,並在初始化時實現了GlideModule配置功能。具體怎麼實現的呢?接下來具體分析一下,在初始化時new 了一個ManifestParser物件並且呼叫了parse()方法返回一個GlideModule型別的List.

在parse()方法中通過getApplicationInfo方法獲取metaData資訊,若有metaData資料(appInfo.metaData != null),如果metaData的值為GlideModule則呼叫parseModule(key),方法返回GlideModule並add到返回的List中。

檢視parseModule(String className)方法

到此我們看到通過反射的方式獲取我們在清單檔案中宣告的自定義的GlideModule物件。在獲取到
GlideModule集合之後,遍歷了集合並呼叫相應的applyOptions和registerComponents方法,而Glide物件的生成是通過GlideBuilder的createGlide方法建立。

看到這都是做的一些初始化操作,並將引數傳遞到Glide構造方法。對於Glide構造方法做的都是一些預設的初始化操作,可以自己去檢視原始碼,此處不再貼出。

通過上面的分析,你就會理解,為什麼之前提到配置資訊只需要實現GlideModule介面,重寫其中的方法,並再清單檔案配置metaData,並且metaData的key是自定義GlideModule的全路徑名,value值必須是GlideModule.會明白當我們不想讓自定義的GlideModule生效時只需要刪除相應的GlideModule。當使用了混淆時為什麼要配置…

requestManager.load

對於load方法也是可以接收String,Url,Integer等型別的過載方法,在這裡,我們拿String型別引數分析。

返回的是DrawableTypeRequest物件,DrawableTypeRequest繼承關係如下

20160918155343574

 

而對於DrawableRequestBuilder類使用的是一個建立者模式,對於常用函式placeholder(),error(),transform等設定都是在此設定,

我們看到最終又呼叫了父類方法

通過檢視父類(GenericRequestBuilder)原始碼你會發現我們每次呼叫placeholder(),error()的等這些方法,其實都是給該類中的變數賦值。

經過一系列操作後,最終呼叫into(imageView)方法來完成圖片的最終載入

建立請求

由上面看到最終呼叫的into方法是

上面都執行都呼叫了 Util.assertMainThread();判斷只能在主執行緒中執行。(更新View當然需要在主執行緒),在Glide中Target我們可以理解成View,只是Glide對我們的View做了一層封裝。
之後通過buildRequest建立請求物件。

最後呼叫obtainRequest方法

最終通過GenericRequest.obtain方法建立了

至此請求物件建立成功,在通過buildRequest建立請求成功後,使用了target.setRequest(request);將請求設定到target,並通過addListener將target加入到lifecycle。上面執行了那麼多都只是請求建立,請求的執行時通過requestTracker.runRequest(request);開始的。

傳送請求

在上面幾句程式碼,我們看到,每次提交請求都將請求加入了一個set中,用它來管理請求,然後通過request的實現類GenericRequest檢視begin方法執行的內容

上面有一句!isComplete() && !isFailed() && canNotifyStatusChanged()判斷,如果都為真會回撥target.onLoadStarted(getPlaceholderDrawable());我們可以看到Target的實現類ImageViewTarget中onLoadStarted的回撥執行語句

現在你是不是有一種柳暗花明又一村的感覺,終於明白為什麼設定placeHolder後,會在載入前有一個佔點陣圖,當然設定載入錯誤圖片佔點陣圖的原理也是一樣的。只不過回撥執行時機不同。

Engine類封裝了資料獲取的重要入口方法,向request層提供這些API,比如load(), release(), clearDiskCache()等方法

我們看到先根據呼叫loadFromCache從記憶體載入,若返回值為空再次從活動的資源中載入,若再次為空檢視jobs是否提交過任務,若沒有提交則建立EngineRunnable,並將任務提交到engineJob中。我們先看下EngineJob中的start方法

接下來看執行緒類EngineRunnable的run方法,它是任務執行的入口

DiskLruCache獲取資料

之後呼叫decodeJob類中的decodeResultFromCache

接下來我們分析decodeFromSource方法

在資料獲取時先呼叫DataFetcher的loadData()拉取資料,對於DataFetcher的實現類有好幾個,我們拿從url拉取資料為例,也就是HttpUrlFetcher類

看到這終於看到了網路載入請求,我們也可以自定義DataFetcher,從而使用其他網路庫,如OkHttp,Volley.

最後我們再看下transformEncodeAndTranscode方法

至此,圖片載入流程已經介紹完畢,當然還有很多的地方沒有提到,相信如果你在閱讀本文的同時,自己跟蹤原始碼會輕鬆很多,如果自己不跟著原始碼走的話,可能這篇文章看幾遍對Glide原理理解的也是雲裡霧裡,或者說當時看的懂,但是很快就不記得。所以切記自己要跟著原始碼過一遍。

本篇文章實在是長,能讀完本文章也是需要一定毅力的…若文章有不足或者錯誤的地方,歡迎指正,以防止給其他讀者錯誤引導。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

詳談高大上的圖片載入框架Glide -原始碼篇 詳談高大上的圖片載入框架Glide -原始碼篇

相關文章