Fresco正傳(3):DraweeHierarchy分析
前言
在正式開始分析之前,還是看一下DraweeHierarchy
的繼承體系,做到心中有數。
看三個類的命名好像也只有SettableDraweeHierarchy
可以猜出來一些 – 可設定的層次結構。
而GenericDraweeHierarchy
你是不是哪裡眼熟?沒錯,在GnericDraweeView
的inflateHierarchy()
的方法中,使用GenericDraweeHierarchyBuilder
構建出了一個DraweeHierarchy
的例項物件。
值得一提的是,DraweeHierarchy
的主要職責是提供可顯示的圖片,也就是Draweable
,而在Fresco中,預設定義了眾多的Drawable
GenericDraweeHierarchy
的得到了充分的使用。
由於Drawable
體系知識我還沒有研究,就先把Fresco自定義的Drawable
的體系脈絡先梳理一下,以便混個眼熟。
ArrayDrawable-FadeDrawable
看一下ArrayDrawable
類的註釋,可以知道:
- 這個Drawable包含其他的顯示元素陣列(層),並且都是以陣列順序繪製的,因此,元素陣列的最大值(最末尾元素)將被繪製在頂部。
- 這個Drawable類似Android的
LayerDrawable
類,但是LayerDrawable
並不支援動態新增和移除圖層。
簡單明瞭,繼續看一下FaseDrawable
- 可以使指定的圖層逐漸消失
- 支援任意數量的影象;有五種不同的方式讓圖層逐漸消失。
- fadeInLayout:淡入指定的圖層直到完全顯示
- fadeOutLayout:淡出指定的圖層直到完全透明
- fadeOutAllLayers:淡出所有的圖層直到完全透明
- fadeToLayer:淡入指定的圖層直到完全顯示,同時淡出其他圖層直到完全透明。
- fadeUpToLayer:淡入一個圖層的集合到指定的圖層並讓指定的圖層完全顯示,同時淡出其他的圖層至完全透明。
ProgressBarDrawable
- 基於
level
的值,顯示一個進度條。
ForwardingDrawable體系
先看一下ForwardingDrawable
類的註釋:
- 目標是代理drawable的功能到一個內部例項。
例如GenericDraweeHierarchy
中的RootDrawable
內部類。
正文
與前一篇文章不同,這次分析DraweeHierarchy
按照從上至下的順序來。
DraweeHierarchy
DraweeeHierarchy
是一個介面,同時介面中也只有一個getTopLevelDraweable()
方法,想要了解其中暗含了那些意圖,只能從註釋入手。
- 為了可以動態改變顯示的影象,
DraweeHierarchy
被組裝成一個樹狀。 - 樹狀的層級比Android傳統的巢狀檢視,更加輕便。
- 樹狀層級的細節被隱藏,外界無法看到。所有的可見的影象,都是最頂級Drawable。
當然,這樣子你可能會更清晰一些。
FaseDraweable
作為頂層影象,隱藏了其與的細節。
SettableDraweeHierarchy
看一下介面註釋,我們能瞭解如下資訊:
SettableDraweeHierarchy
介面代表可設定的層級結構。直到實際的圖片被顯示之前,它應該顯示一張佔位圖;如果載入失敗了,層級結構應該可以選擇一張失敗的圖片用於顯示。- 這些方法只能被Controller所呼叫。
此外,本介面還提供瞭如下方法:
- 影象可以被重置
- 影象可以設定進度
- 設定失敗
- 設定重試
- 設定controllerOverlay
為了便於理解,還是給出層級結構的兩種不同的表示方式。
GenericDraweeHierarchy
作為抽象介面的實現類,無非就是在原本抽象特性的基礎上,又增加了一些其他的特性。
通過類註釋,來粗略的看一下本類都做了些什麼。
- 一個可設定的層級結構在成功顯示實際圖片前,會一直顯示佔位圖。
- 如果提供了失敗的圖片,失敗的圖片將會被用於失敗的情況下。
- 如果提供了重試的圖片,重試的圖片將會被用於失敗並且重試可用的情況下。
- 如果提供了進度條,進度條會被一直顯示直至載入完畢。
這樣,層次結構就好像下面這個樣子,從上至下依次執行狀態:
分析完了基本脈絡,接下來看看具體的程式碼是怎麼做的。想例項化GnericDraweeHierarchy
類,必須要走構造方法,不過估計看到龐大的構造方法你就會眼暈。同時,想要構造方法必須要傳入GenericDraweeHierarchyBuilder
的一個例項。
GenericDraweeHierarchy(GenericDraweeHierarchyBuilder builder) {
// ... 省略N行,構造GenericDraweeHierarchy的程式碼。
}
在構造方法上按ALT+F7
,看看在哪裡呼叫了它。結果發現只有在GenericDraweeHierarchyBuilder
的build()
方法中被呼叫了。
public GenericDraweeHierarchy build() {
validate();
return new GenericDraweeHierarchy(this);
}
根據前一篇部落格的分析,可以知道,在解析XML屬性時,例項化了GenericDraweeHierarchyBuild
類,並使用建造者模式,構建出了GenericDraweeHierarchy
的例項物件。這樣,這兩端DraweeHierarchy
和DraweeView
就被我們串聯起來了。
再回到GenericDraweeHierarchy
類的構造方法中,其實內部做的操作就是上圖的對映,就是更加程式碼化了:
- 使用
numLayers
記錄層級總數,每建立一個分子就+1。 - 建立佔位圖分支,如果使用者未自定義,給一個透明的佔位圖;該分支是否需要圓角效果;該分支是否需要包裹縮放效果。此處的
waybeWrapWithScaleType()
的是包裝設計模式的應用。 - 建立例項影象分支,預設給一個透明圖;該分支是否需要縮放效果;是否需要Matrix效果;設定顏色過濾器;
- 建立進度條分支,判斷該分支是否需要縮放效果;
- 建立重試分支,判斷該分支是否需要縮放效果;
- 建立失敗分支,判斷該分支是否需要縮放效果;
- 建立覆蓋層分支
- 根據層級總數,建立一個Drawable陣列,並將填入對應的分支。隨後使用該陣列構造一個
FadeDrwable
類的例項(這個前文提過)。判斷是否需要對FadeDrawable
的例項應用圓角效果。最後,使用最後的Drawable構造一個RootDrawable
的例項,並作為最頂層的影象(mTopLevelDrawable
),其中RootDrawable
是ForwardingDrawable
的子類,起到了代理作用。
就簡單來說,將各種場景的Drawable放入一個數組中,幷包裝成FadeDrawable
以便在各種場景間切換,並根據其構造一個代理物件,以便新增一些需求。
一圖勝千言,希望我畫的圖各位能看懂:O(∩_∩)O哈哈~
最後
DraweeHierarchy的體系分析就基本完成了,如果覺得對您有幫助,多多留言哦。