寫在以前html
上一篇博文寫的是Picasso基本使用和源碼徹底解析,Picasso的源碼閱讀起來仍是很順暢的,而後就想到Glide框架,網上你們也都推薦使用這個框架用來加載圖片,正好我目前的寫做目標也是分析當前一些流行的框架源碼,那就也來解析下Glide的源碼吧,並且有了Picasso源碼的分析相信很快就搞定Glide的,結果也就悲劇了,深陷其中沒法自拔了,Glide的源碼遠非Picasso能比,閱讀起來也是至關的困難的,並且我使用的是最新的Glide4.0,與以前版本有較大的差別,網上也沒能夠參考的資料,這就悲劇了,苦頭專研唄。直到今天才從深溝中冒出頭了,差點憋死,哈哈。python
正文git
Glide的使用和Picasso基本同樣,這裏就再也不多說,主要是由於源碼分析會寫的很長很細,再加上基本使用的話,就更加長了,並且上一篇已寫過Picasso的基本使用,這二者在使用方面相差的微乎及微,因此咱們這篇文章直接進入源碼分析。github
首先在build.gradle裏添加以下引用:設計模式
compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
這裏我用的是Glide4.0也是最新的版本,和3.X在源碼上仍是有很大的差異的。看過3.X源碼的相信對比下這篇文章就會知道。緩存
ok,和Picasso的分析模式同樣,咱們也是從下面最簡單的代碼進行一步一步的深刻分析:微信
Glide.with(MainActivity.this).load(url).into(headerImage);
首先咱們來看看當咱們調用Glide的with方法那作了哪些工做:網絡
with方法中能夠接受Context,Activity,FragmentActivity,Fragment甚至是View不一樣的類型,返回的是RequestManager對象,這個對象是須要在RequestManagerRetriever中獲取的,那咱們在來看看RequestManagerRetriever是怎麼獲取到的?請看getRetriever方法的源碼:app
getRetriever方法中也沒有真正的建立RequestManagerRetriever對象,而是從Glide的getRequestManagerRetriever方法中獲取,那麼很明顯的能夠看出所作的工做都是在Glide的get方法中完成的,在來看下get方法源碼:框架
來到這一步,咱們看到了很是熟悉的代碼設計原理,那就是雙重加鎖的單例模式保證Glide對象的惟一性,那麼initGlide就是建立Glide對象的方法了,請看:
這是initGlide方法中最重要的代碼,主要是建立了一個GlideBuilder對象,而後調用build方法來完成Glide對象的建立,相信不用看bulid方法,你們也會猜到接下來將要發生什麼樣的事情,沒錯,那就是使用建造者設計模式來完美的構建出Glide對象:
public Glide build(Context context) { if (sourceExecutor == null) { sourceExecutor = GlideExecutor.newSourceExecutor(); } if (diskCacheExecutor == null) { diskCacheExecutor = GlideExecutor.newDiskCacheExecutor(); } if (memorySizeCalculator == null) { memorySizeCalculator = new MemorySizeCalculator.Builder(context).build(); } if (connectivityMonitorFactory == null) { connectivityMonitorFactory = new DefaultConnectivityMonitorFactory(); } if (bitmapPool == null) { int size = memorySizeCalculator.getBitmapPoolSize(); bitmapPool = new LruBitmapPool(size); } if (arrayPool == null) { arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes()); } if (memoryCache == null) { memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize()); } if (diskCacheFactory == null) { diskCacheFactory = new InternalCacheDiskCacheFactory(context); } if (engine == null) { engine = new Engine(memoryCache, diskCacheFactory, diskCacheExecutor, sourceExecutor, GlideExecutor.newUnlimitedSourceExecutor()); } RequestManagerRetriever requestManagerRetriever = new RequestManagerRetriever( requestManagerFactory); return new Glide( context, engine, memoryCache, bitmapPool, arrayPool, requestManagerRetriever, connectivityMonitorFactory, logLevel, defaultRequestOptions.lock()); }
build方法中主要是構建線程池(包括sourceExecutor ,diskCacheExecutor ),緩存大小和緩存器,默認的鏈接監聽工廠(connectivityMonitorFactory ),Engine對象和RequestManagerRetriever 對象等等。
有幾個重要的對象建立,咱們這裏先看下它的構建內容:
1 Engine對象
建立Engine對象在構造方法中傳遞了幾個重要的參數,分別是線程池,內存緩存和硬盤緩存對象,那咱們來看看在構造方法中它是怎麼構建Engine對象的:
Engine(MemoryCache cache, DiskCache.Factory diskCacheFactory, GlideExecutor diskCacheExecutor, GlideExecutor sourceExecutor, GlideExecutor sourceUnlimitedExecutor, Map<Key, EngineJob<?>> jobs, EngineKeyFactory keyFactory, Map<Key, WeakReference<EngineResource<?>>> activeResources, EngineJobFactory engineJobFactory, DecodeJobFactory decodeJobFactory, ResourceRecycler resourceRecycler) { this.cache = cache; this.diskCacheProvider = new LazyDiskCacheProvider(diskCacheFactory); if (activeResources == null) { activeResources = new HashMap<>(); } this.activeResources = activeResources; if (keyFactory == null) { keyFactory = new EngineKeyFactory(); } this.keyFactory = keyFactory; if (jobs == null) { jobs = new HashMap<>(); } this.jobs = jobs; if (engineJobFactory == null) { engineJobFactory = new EngineJobFactory(diskCacheExecutor, sourceExecutor, sourceUnlimitedExecutor, this); } this.engineJobFactory = engineJobFactory; if (decodeJobFactory == null) { decodeJobFactory = new DecodeJobFactory(diskCacheProvider); } this.decodeJobFactory = decodeJobFactory; if (resourceRecycler == null) { resourceRecycler = new ResourceRecycler(); } this.resourceRecycler = resourceRecycler; cache.setResourceRemovedListener(this); }
建立了幾個工廠對象方法,好比EngineKeyFactory,EngineJobFactory和DecodeJobFactory,幾個HashMap類型的對象集合,如:jobs ,activeResources 等等,而後就分別把這些對象賦值給Engine的成員變量,那麼來看下建立Engine對象時到底初始化了那些成員變量:
ok,Engine是一個很是重要的對象,後面扮演着重要的角色,爲了方面理解它所擁有那些可以使用的對象,這裏我作了個類圖顯示的標了出來。
2 RequestManagerRetriever 對象
再來看看RequestManagerRetriever 對象的建立,這個相對的簡單不少,咱們來看下它的構造方法:
因爲咱們傳遞過來的requestManagerFactory爲空,因此factory將會使用默認的DEFAULT_FACTORY工廠,DEFAULT_FACTORY是真正建立RequestManager對象的地方,稍後介紹。
這裏只是讓你們知道這裏的factory就是DEFAULT_FACTORY。
來看看它擁有哪些成員:
3 Glide對象
在build方法中 return new Gilde(),建立一個Glide對象並返回,那在Gilde構造方法中作了哪些初始化工做呢?
Glide( Context context, Engine engine, MemoryCache memoryCache, BitmapPool bitmapPool, ArrayPool arrayPool, RequestManagerRetriever requestManagerRetriever, ConnectivityMonitorFactory connectivityMonitorFactory, int logLevel, RequestOptions defaultRequestOptions) { this.engine = engine; this.bitmapPool = bitmapPool; this.arrayPool = arrayPool; this.memoryCache = memoryCache; this.requestManagerRetriever = requestManagerRetriever; this.connectivityMonitorFactory = connectivityMonitorFactory; DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT); bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat); final Resources resources = context.getResources(); registry = new Registry(); registry.register(new DefaultImageHeaderParser()); registry.register()...append()... ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory(); glideContext = new GlideContext(context, registry, imageViewTargetFactory, defaultRequestOptions, engine, this, logLevel); }
這裏首先是把傳遞進來的參數賦值給成員變量,而後建立了幾個重要的對象:
①:Registry對象
Registry主要是添加不少的註冊或解析方式等,這在後面用來解析是從內存,文件或是網絡獲取資源有着重要的做用,並且它每一類解析方式都會提供多個方法,一種方式獲取不到將會使用另一種,知道獲取到資源爲止,來看下它的register和append方法:
主要是存放到不一樣的對象中的集合變量中。
②:GlideContext對象
GlideContext對象在後面也扮演中重要的角色,建立這個對象到目前爲止只是爲了初始化和賦值:
總結下Glide,Registry和GlideContext對象所初始化的參數:
這是到目前對象所擁有的成員方法和成員變量。
ok,再回到上面build方法,在返回Glide對象後,調用getRequestManagerRetriever()從而獲取到RequestManagerRetriever對象,從上面Glide類圖咱們也能夠看出,Glide對象已包含RequestManagerRetriever對象。
再往上返回一步,在getRetriever(activity)方法中獲取到RequestManagerRetriever對象後,調用get(activity)來獲取RequestManager對象,那麼咱們來看看它是怎麼獲取到的?
首先判斷是否在子線程執行,不然就調用supportFragmentGet方法來獲取RequestManager對象,那麼來看下它的源碼:
還記得咱們的RequestManagerRetriever擁有哪些成員嗎,不記得就去看看上面它的類圖吧,由它的源碼咱們能夠看到它將會使用factory並調用它的build方法,還記得factory是什麼嗎?上面已分析factory就是DEFAULT_FACTORY,那來看看它的源碼實現:
在build中建立一個RequestManager對象並返回,來看下RequestManager的構造方法中作了哪些操做:
RequestManager( Glide glide, Lifecycle lifecycle, RequestManagerTreeNode treeNode, RequestTracker requestTracker, ConnectivityMonitorFactory factory) { this.glide = glide; this.lifecycle = lifecycle; this.treeNode = treeNode; this.requestTracker = requestTracker; final Context context = glide.getGlideContext().getBaseContext(); connectivityMonitor = factory.build(context, new RequestManagerConnectivityListener(requestTracker)); if (Util.isOnBackgroundThread()) { mainHandler.post(addSelfToLifecycle); } else { lifecycle.addListener(this); } lifecycle.addListener(connectivityMonitor); setRequestOptions(glide.getGlideContext().getDefaultRequestOptions()); glide.registerRequestManager(this); }
主要是賦值,添加生命週期監聽器,設置請求屬性,以及註冊請求管理器,代碼仍是很簡單的,都能看的明白。
來看下它的類圖:
ok,到此,咱們的with方法中獲取RequestManager對象就已完成。
來看下with方法執行的順序圖:
注:流程圖看不清楚,能夠選擇在「新標籤中打開圖片」查看。
在調用with方法獲取到RequestManager對象的前提下,調用load方法,並傳遞咱們的url參數,來看下它的源碼:
這裏並無直接的去加載咱們的url獲取資源,而是首先調用asDrawable方法來配置圖片的信息,其實就是說加載獲取的圖片資源是轉換爲drawale或是bitmap或是gif進行圖片顯示,默認的是使用drawale,你也可使用asGif()/asBitmap()來設置它是已什麼形式來展現。這裏咱們按默認的方式來分析。
load方法目的是爲了獲取RequestBuilder對象,下面來一步步分解它源碼:
首先來看下asDrawable()的源碼:
asDrawable()中首先調用as方法,並傳進Drawable.class做爲參數,來看下as方法的源碼:
由as方法,咱們可看到它直接的建立一個RequestBuilder對象,並傳遞了相關的參數進去,這裏要注意下resourceClass就是Drawable.class這裏在後面有個選擇分支時使用到。
來看下RequestBuilder的構造方法中作了哪些初始化佈局。
很簡單的賦值,這裏也須要注意的是transcodeClass就是Drawable.class類。
ok,獲取到RequestBuilder對象後,它又作了進一步的賦值操做,就是在transition方法中,
把建立的DrawableTransitionOptions對象賦值給transitionOptions變量。
ok,再往上來看,完成asDrawable方法對RequestBuilder的建立後才調用load方法來傳遞咱們的url地址,其實在load也沒有作什麼事,就是一箇中轉站,轉給了loadGeneric方法,來看:
在loadGeneric方法中也沒作其餘太多的操做,也是保存了咱們的url而且isModelSet設置爲true,意思就是說Model已有設置了。來看下它的類圖:
它到目前爲止所包含的成員變量和方法都在此。
ok,到此咱們的load方法也分析完畢,來看下它的流程圖:
注:流程圖看不清楚,能夠選擇在「新標籤中打開圖片」查看。
因爲Glide源碼非常複雜,寫的很長,因此只能分兩篇來發布,第一篇分析了Glide的with和load方法源碼,第二篇將會分析into方法,說實在的into方法複雜程度遠超過with和load方法總和,可是不要緊,仍是保持一向的風格,一步步的分析其執行流程,相信你們學完確定能徹底的掌握它的源碼結構。
ok,今天就先發布這一篇吧。
各位若是還有哪裏不明白的,或是我這裏講的還不夠透徹,亦或是講錯了的地方請留言指正,讓咱們共同進步,謝謝
同時,請你們掃一掃關注個人微信公衆號,雖然寫的不是很勤,可是每一篇都有質量保證,讓您學習到真正的知識。