1. 程式人生 > >Fresco正傳(3):DraweeHierarchy分析

Fresco正傳(3):DraweeHierarchy分析

前言

在正式開始分析之前,還是看一下DraweeHierarchy的繼承體系,做到心中有數。

看三個類的命名好像也只有SettableDraweeHierarchy可以猜出來一些 – 可設定的層次結構。

GenericDraweeHierarchy你是不是哪裡眼熟?沒錯,在GnericDraweeViewinflateHierarchy()的方法中,使用GenericDraweeHierarchyBuilder構建出了一個DraweeHierarchy的例項物件。

值得一提的是,DraweeHierarchy的主要職責是提供可顯示的圖片,也就是Draweable,而在Fresco中,預設定義了眾多的Drawable

類,並在GenericDraweeHierarchy的得到了充分的使用。

由於Drawable體系知識我還沒有研究,就先把Fresco自定義的Drawable的體系脈絡先梳理一下,以便混個眼熟。

ArrayDrawable-FadeDrawable

看一下ArrayDrawable類的註釋,可以知道:

  1. 這個Drawable包含其他的顯示元素陣列(層),並且都是以陣列順序繪製的,因此,元素陣列的最大值(最末尾元素)將被繪製在頂部。
  2. 這個Drawable類似Android的LayerDrawable類,但是LayerDrawable並不支援動態新增和移除圖層。

簡單明瞭,繼續看一下FaseDrawable

類的註釋:

  1. 可以使指定的圖層逐漸消失
  2. 支援任意數量的影象;有五種不同的方式讓圖層逐漸消失。
    1. fadeInLayout:淡入指定的圖層直到完全顯示
    2. fadeOutLayout:淡出指定的圖層直到完全透明
    3. fadeOutAllLayers:淡出所有的圖層直到完全透明
    4. fadeToLayer:淡入指定的圖層直到完全顯示,同時淡出其他圖層直到完全透明。
    5. fadeUpToLayer:淡入一個圖層的集合到指定的圖層並讓指定的圖層完全顯示,同時淡出其他的圖層至完全透明。

ProgressBarDrawable

  1. 基於level的值,顯示一個進度條。

ForwardingDrawable體系

先看一下ForwardingDrawable類的註釋:

  1. 目標是代理drawable的功能到一個內部例項。

例如GenericDraweeHierarchy中的RootDrawable內部類。

正文

與前一篇文章不同,這次分析DraweeHierarchy按照從上至下的順序來。

DraweeHierarchy

DraweeeHierarchy是一個介面,同時介面中也只有一個getTopLevelDraweable()方法,想要了解其中暗含了那些意圖,只能從註釋入手。

  1. 為了可以動態改變顯示的影象,DraweeHierarchy被組裝成一個樹狀。
  2. 樹狀的層級比Android傳統的巢狀檢視,更加輕便。
  3. 樹狀層級的細節被隱藏,外界無法看到。所有的可見的影象,都是最頂級Drawable。

當然,這樣子你可能會更清晰一些。

FaseDraweable作為頂層影象,隱藏了其與的細節。

SettableDraweeHierarchy

看一下介面註釋,我們能瞭解如下資訊:

  1. SettableDraweeHierarchy介面代表可設定的層級結構。直到實際的圖片被顯示之前,它應該顯示一張佔位圖;如果載入失敗了,層級結構應該可以選擇一張失敗的圖片用於顯示。
  2. 這些方法只能被Controller所呼叫。

此外,本介面還提供瞭如下方法:

  1. 影象可以被重置
  2. 影象可以設定進度
  3. 設定失敗
  4. 設定重試
  5. 設定controllerOverlay

為了便於理解,還是給出層級結構的兩種不同的表示方式。

GenericDraweeHierarchy

作為抽象介面的實現類,無非就是在原本抽象特性的基礎上,又增加了一些其他的特性。

通過類註釋,來粗略的看一下本類都做了些什麼。

  1. 一個可設定的層級結構在成功顯示實際圖片前,會一直顯示佔位圖。
  2. 如果提供了失敗的圖片,失敗的圖片將會被用於失敗的情況下。
  3. 如果提供了重試的圖片,重試的圖片將會被用於失敗並且重試可用的情況下。
  4. 如果提供了進度條,進度條會被一直顯示直至載入完畢。

這樣,層次結構就好像下面這個樣子,從上至下依次執行狀態:

分析完了基本脈絡,接下來看看具體的程式碼是怎麼做的。想例項化GnericDraweeHierarchy類,必須要走構造方法,不過估計看到龐大的構造方法你就會眼暈。同時,想要構造方法必須要傳入GenericDraweeHierarchyBuilder的一個例項。

 GenericDraweeHierarchy(GenericDraweeHierarchyBuilder builder) {
     // ... 省略N行,構造GenericDraweeHierarchy的程式碼。
 }

在構造方法上按ALT+F7,看看在哪裡呼叫了它。結果發現只有在GenericDraweeHierarchyBuilderbuild()方法中被呼叫了。

public GenericDraweeHierarchy build() {
    validate();
    return new GenericDraweeHierarchy(this);
}

根據前一篇部落格的分析,可以知道,在解析XML屬性時,例項化了GenericDraweeHierarchyBuild類,並使用建造者模式,構建出了GenericDraweeHierarchy的例項物件。這樣,這兩端DraweeHierarchyDraweeView就被我們串聯起來了。

再回到GenericDraweeHierarchy類的構造方法中,其實內部做的操作就是上圖的對映,就是更加程式碼化了:

  1. 使用numLayers記錄層級總數,每建立一個分子就+1。
  2. 建立佔位圖分支,如果使用者未自定義,給一個透明的佔位圖;該分支是否需要圓角效果;該分支是否需要包裹縮放效果。此處的waybeWrapWithScaleType()的是包裝設計模式的應用。
  3. 建立例項影象分支,預設給一個透明圖;該分支是否需要縮放效果;是否需要Matrix效果;設定顏色過濾器;
  4. 建立進度條分支,判斷該分支是否需要縮放效果;
  5. 建立重試分支,判斷該分支是否需要縮放效果;
  6. 建立失敗分支,判斷該分支是否需要縮放效果;
  7. 建立覆蓋層分支
  8. 根據層級總數,建立一個Drawable陣列,並將填入對應的分支。隨後使用該陣列構造一個FadeDrwable類的例項(這個前文提過)。判斷是否需要對FadeDrawable的例項應用圓角效果。最後,使用最後的Drawable構造一個RootDrawable的例項,並作為最頂層的影象(mTopLevelDrawable),其中RootDrawableForwardingDrawable的子類,起到了代理作用。

就簡單來說,將各種場景的Drawable放入一個數組中,幷包裝成FadeDrawable以便在各種場景間切換,並根據其構造一個代理物件,以便新增一些需求。

一圖勝千言,希望我畫的圖各位能看懂:O(∩_∩)O哈哈~

最後

DraweeHierarchy的體系分析就基本完成了,如果覺得對您有幫助,多多留言哦。