Fresco正傳(2):DraweeView分析
正文
既然要分析DraweeView
,那麼就先看一下DraweeView
的主要整合體系,然後在詳細分析一下都做了些什麼事情。
在看潘永強部落格的時候,其中他提到:原始碼的分析分為廣度和深度,先廣度再深度,但是都要適當,避免陷入無止境的廣度和深度的細節中去。
從這麼多篇博文來看,原始碼的分析從上至下、先父類後子類、先構造再細節的分析思路是非常棒的。但是,每個人分析習慣不一樣,就我來說更喜歡先從更易接觸的類再深入父類、先看類註釋再看詳細的方法。後續的部落格也會基本按照此種思路。
SimpleDraweeView
是官方文件中,我們最先接觸類,也是最易使用的類。那麼就從這個類入手,一步一步分析。先上一下繼承體系圖,雖不是從上至下的分析,但是也需要充分了解體系結構。
好的開發框架,在命名方面往往做的非常好,起到見名知意作用。那麼,我們就從自己的開發經驗推測一下每個類都做了什麼。
SimpleDraweeView
是簡單控制元件的意思,既然是簡單,就會提供出簡單明瞭、便易使用的方法,我想setImageURI(Uri uri)
就是這樣一個方法。
GenericDraweeView
是通用控制元件的意思,通過上一篇文章知道,DraweeView
體系中,持有了DraweeHierarchy
和DraweeController
的引用,那麼預設的東西,會不會是在這個類中提供的?。
DraweeView
是什麼意思呢?,只從命名來看推測不出來什麼。
SimpleDrawee
要分析一個類,就先看他的類註釋。
/**
* This view takes a uri as input and internally builds and sets a controller.
* This class must be statically initialized in order to be used.
* If you are using the Fresco * image pipeline, use Fresco#initialize to do this.
*/
- 這個控制元件接收URI作為輸入,並在內部建立和設定一個控制器。
- 這個類必須被靜態初始化才能夠被使用,如果你想使用Fresco預設的圖片管道來載入圖片,請使用Fresco的initlialize去做這件事。
相關注釋一定會體現為程式碼表示,我們很輕鬆就能夠找到做第一件事情的程式碼:
/**
* Displays an image given by the uri.
*/
public void setImageURI(Uri uri, @Nullable Object callerContext) {
DraweeController controller = mSimpleDraweeControllerBuilder
.setCallerContext(callerContext)
.setUri(uri)
.setOldController(getController())
.build();
setController(controller);
}
通過uri展示一張圖片。在其內部,通過mSimpleDraweeControllerBuilder
建造了一個DraweeController
物件,並通過setController()
方法,將控制器設定給了頂層的DraweeView
類,當前從目前來看是這個樣子的。而一般以Builder
結尾的都是使用了建造者模式的類。
這是一個學習設計模式的部落格。
mSimpleDraweeControllerBuilder
是一個成員變數,搜尋一下它在哪裡被賦值的。
來到了init()
方法,此方法被各個建構函式所呼叫。
private void init() {
if (isInEditMode()) {
return;
}
Preconditions.checkNotNull(sDraweeControllerBuilderSupplier, "SimpleDraweeView was not initialized!");
mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get();
}
雖然,程式碼不多,還是值得解釋一下。isInEditMode()
是判斷當前是否是預覽模式或者是編輯模式,通常在AndrdioStudio中預覽佈局時,會碰到自定義控制元件顯示不出來的情況,加上這句話就可以了。
而Preconditions.checkNotNull()
是Fresco的工具類,從命名來看,就是檢查相關引用是否不為空,為空則直接報錯.
下面一句則是,從Supplier
(提供者、供應商)中獲取一個SimpleDraweeContoller
的建造器。特別說明的是,Supplier
雖然不是某種設計模式之一,但是在Fresco被廣泛使用,它可是提供單個物件型別的類,在語義上它可能是一個工廠、建造、或其他任意的東西。
sDraweeControllerBuilderSupplier
是一個靜態成員變數,它的初始化就聯絡到了本類所做的第二件事,使用Fresco.initialize(Context)
來初始化本類。
既然需要適當在廣度上擴充套件,就接著看一下Fresco
類。根據類的註釋,可以知道:
- 這個類是Fresco的切入點。
- 在使用這個類之前,你必須初始化此類。而一種簡單初始化的方式就是呼叫
Fresco.initialize(Context)
。
既然有簡單的,那麼就有非簡單的,一共有兩種方式:
/** Initializes Fresco with the default config. */
public static void initialize(Context context) {
ImagePipelineFactory.initialize(context);
initializeDrawee(context);
}
/** Initializes Fresco with the specified config. */
public static void initialize(Context context, ImagePipelineConfig imagePipelineConfig) {
ImagePipelineFactory.initialize(imagePipelineConfig);
initializeDrawee(context);
}
其中提到了預設的配置和指定的配置,這裡不做過多的深入,對於指定的配置(也就兩個引數的方法),你只需要知道在ImagePipelineConfig
中有著大量的引數配置,以保證Fresco框架的可配置化,由於內部引數過多使用了建造者模式來解耦程式碼。
見名知意,ImagePipelineFactory.initialize(context)
就是對配置初始化,這裡就先略過了。
這樣就引申到了initializeDrawee(Context context)
方法:
private static void initializeDrawee(Context context) {
sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context);
SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
}
這段程式碼非常重要,它決定了Fresco使用的預設控制器是名為:PipelineDraweeController
的類,先簡略看一下類註釋,該Controller是圖片載入器與Model的橋樑,也就是說,如何使用ImagePipeline
載入圖片,並交給Model都是在這個類中控制的。當然,這也符合MVC模式的設計。
Drawee controller that bridges the image pipeline with {@link SettableDraweeHierarchy}.
接著就呼叫到了SimpleDraweeView
靜態初始化的方法。這樣,從Fresco
初始化到SimpleDraweeView
的初始化至呼叫setImageUri()
顯示一張圖片的流程就基本完整了。
給出一個示意圖,這個圖既非UML圖、也非流程圖,僅僅表達一些程式碼過程,個人覺得使用圖形更形象一些:
GenericDraweeView
從類註釋入手可以瞭解,本類的功能主要是通過解析XML的屬性來構建出一個通用的Hierarchy
並進行設定。此外,還提供了一個設定控制元件寬高比的方法。
本類比較簡單,核心的方法在於inflateHierarchy(Context context, @Nullable AttributeSet attrs)
。
方法只做的三件事:
1. 解析XML屬性
2. 使用建造者模式構建GenericDraweeHierarchy
3. 將Hierarchy
設定給DraweeView
體系
private void inflateHierarchy(Context context, @Nullable AttributeSet attrs) {
Resources resources = context.getResources();
// 解析XML屬性
if (attrs != null) {
}
// 使用建造者模式,構建Hierarchy
GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources);
// ... ...
// 為DraweeView體系設定hierarchy
setHierarchy(builder.build());
}
到此,值得注意的是。與DraweeView
有關的DraweeHierarchy
和DraweeController
均已出現,DraweeHierarchy
對應的預設實現類是:GenericDraweeHierarchy
;DraweeController
對應的預設實現類是:PipelineDraweeController
。
此外,本類做的第二件事,請參考博文:控制寬高比
DraweeView
先上一張圖,更簡潔的表達目的和想做的事。
還是先從類的註釋入手吧。從註釋中可以瞭解到如下幾件事:
- 該控制元件用於展示從
DraweeHierarchy
獲取的影象。 - 使用此控制元件之前,應該先為其設定
DraweeHierarchy
。由於建立一個DraweeHierarchy
是一個昂貴的操作,推薦在建立的時候只做一次。 - 為了展示一張圖片,
DraweeController
必須被設定。 - Note:雖然這個控制元件是ImageView的直接子類,但是不支援ImageView的眾多方法。
在這個類中,即將接觸到一個其背後的男人DraweeHolder
類,可以說DraweeView
類中所做的所有操作,都是直接或者間接和DraweeHolder
有關係的。DraweeView
從其體系中獲取到的DraweeHierarchy
和DraweeController
的資訊都被其轉交到了DraweeHolder
類中。其實,這個就是一個解耦操作。假設,你想要自定一個控制元件,只想使用DraweeHierarchy
和DraweeController
的功能,難道還自己持有這兩個類的引用? Just So So。DraweeHolder
幫你省去了很多麻煩。
先看一下DraweeHolder
是如何被建立的。
private void init(Context context) {
...
mDraweeHolder = DraweeHolder.create(null, context);
...
}
看樣子平平無償,瀏覽該類的其他方法你會發現,大部分的操作都是將資訊轉交給DraweeHolder
的操作。但是,請不要忽略以下兩個方法:
public void setController(@Nullable DraweeController draweeController) {
mDraweeHolder.setController(draweeController);
// 重點
super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
}
public void setHierarchy(DH hierarchy) {
mDraweeHolder.setHierarchy(hierarchy);
// 重點
super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
}
注意到了兩個重點沒?mDraweeHolder.getTopLevelDrawable()
獲取到的就是DraweeHierarchy.getTopLevelDraweeable()
。
從之前的分析可以得知,setHierarchy()
是先被呼叫而後才是setController()
,
通過super.setImageDrawable(mDraweeHolder.getTopLevelDrawable())
這句話,就將Fresco的圖片顯示與ImageView結合了起來,這也是圖片能夠顯示的原因。
如果你自定義控制元件了,千萬不要忘記模仿這兩個方法加上同樣的語句哦。
既然,DraweeView
已經將職責都轉交給了DraweeHolder
類,那麼就來看看DraweeHolder
類做了些什麼。
還是先從類註釋入手:
- 這個類持有了
DraweeController
和DraweeHierarchy
- 這個類便於自定義控制元件使用
在瀏覽類的所有方法時,onAttach()
和onDetach()
方法引起了我的注意。
public void onAttach() {
mEventTracker.recordEvent(Event.ON_HOLDER_ATTACH);
mIsHolderAttached = true;
attachOrDetachController();
}
public void onDetach() {
mEventTracker.recordEvent(Event.ON_HOLDER_DETACH);
mIsHolderAttached = false;
attachOrDetachController();
}
通過註釋可以知道onAttach()
的核心作用是獲取DraweeController
以顯示影象;onDetach()
的核心作用是釋放用於顯示影象的資源。他們都共同呼叫了attachOrDetachController()
方法。
private void attachOrDetachController() {
if (mIsHolderAttached && mIsVisible && mIsActivityStarted) {
attachController();
} else {
detachController();
}
}
你會發現,當同時滿足onAttach()
被呼叫、控制元件可見時、Activity啟動時才會呼叫attachController()
方法,既然需要同時滿足這麼多條件,想來這一定是個非常重要的方法。
可以說,Fresco核心載入的邏輯都是由這段程式碼引出的。
private void attachController() {
if (mIsControllerAttached) {
return;
}
mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);
mIsControllerAttached = true;
if (mController != null && mController.getHierarchy() != null) {
mController.onAttach();
}
}
private void detachController() {
if (!mIsControllerAttached) {
return;
}
mEventTracker.recordEvent(Event.ON_DETACH_CONTROLLER);
mIsControllerAttached = false;
if (mController != null) {
mController.onDetach();
}
}
其中mIsControllerAttached
是保證核心邏輯在一個控制元件中只被執行一次。在attachController()
方法中,如果同時滿足了DraweeController
不為空和DraweeHierarchy
不為空,才會呼叫DraweeController
的onAttach()
方法。
到了這裡,你是不是非常好奇在DraweeController
的onAttach()
的方法中,到底做了怎麼樣重要的邏輯? (^__^) 嘻嘻……
最後
DraweeView的體系分析就基本完成了,如果覺得對您有幫助,多多留言哦。
相關推薦
Fresco正傳(2):DraweeView分析
正文 既然要分析DraweeView,那麼就先看一下DraweeView的主要整合體系,然後在詳細分析一下都做了些什麼事情。 在看潘永強部落格的時候,其中他提到:原始碼的分析分為廣度和深度,先廣度再深度,但是都要適當,避免陷入無止境的廣度和深度的細節中去。
Fresco正傳(3):DraweeHierarchy分析
前言 在正式開始分析之前,還是看一下DraweeHierarchy的繼承體系,做到心中有數。 看三個類的命名好像也只有SettableDraweeHierarchy可以猜出來一些 – 可設定的層次結構。 而GenericDraweeHierarchy你
Fresco前傳(2):原始碼分析 DraweeHierarchy/DraweeView/DraweeController
前言 Fresco的中文文件,最正宗的使用方法,當然在文件中尋找。 正文 DraweeHierarchy/DraweeView/DraweeController Fresco是一個圖片請求載入處理框架,整體架構是MVC模式 (DraweeHier
個人作業2:網站分析之慕課網
配置 一次 adding tar 可能 經理 不同 自己的 同方 產品名 慕課網(網站) 選擇原因 目前使用比較頻繁的網站,也是程序員必備的一個網站 第一部分調研,評測 1、第一次上手體驗。 首頁分類清楚,可以根據課程,職業路徑,還可以使用模糊查詢,根據需
團隊作業2:需求分析&原型設計
符號 原型設計工具 日期 clas max 獲得 痛苦 組合 人員 Deadline: 2017-11-5 22:00PM,以博客發表日期為準。 評分基準: 按時交 - 有分,檢查的項目包括後文的三個方面 需求分析 原型設計 編碼規範 晚交
Ionic開發2:目錄分析及創建組件
n-n 數據 bootstra 只需要 public 是我 sele 元數據 output 上一篇我們創建好了一個新項目。 現在用VScode打開這個目錄並且觀察: node_modules :node 各類依賴包 resources :android/ios 資源(
Fresco正傳(7):如何手動清理Fresco的快取。
前言 這篇是隨手寫的,有博友在樓下提問相關問題。 這裡先把我知道的方案放這裡,以後有空詳細寫。 另外,請注意:雖然我找到了如何清理快取的方法,但是目前還未實際測試過。請自行測試哦。 正文 public class ImagePipelineCo
YII框架分析筆記2:組件和事件行為管理
reac 設置 有變 相關 article class ces col cal Yii是一個基於組件、用於開發大型 Web 應用的高性能 PHP 框架。CComponent幾乎是所有類的基類,它控制著組件與事件的管理,其方法與屬性如下,私有變量$_e數據存放事件(evnet
軟工作業2:硬幣遊戲——代碼的分析與改進
lis com color detail ogl .com commit mon atp 目的: Python 程序閱讀理解 學習Python 編碼風格指南中譯版(Google SOC), 改進Python程序 如何設計遊戲規則,使得慈善事業可持續。 地鐵口放置硬幣箱
個人作業2:APP案例分析
似的 第一時間 為我 style href 程序出錯 朋友 bsp oca 鐵路12306案例分析 第一部分 調研, 評測 1.下載軟件並使用起來,描述最簡單直觀的個人第一次上手體驗。 鐵路12306app第一次使用的時候讓人感覺界面簡潔明
集美大學1414班軟件工程個人作業2——個人作業2:APP案例分析
代碼 美工 總計 val 需求分析 get gui 背景 優點 一、作業鏈接 個人作業2:APP案例分析 二、博文要求 通過分析你選中的產品,結合閱讀《構建之法》,寫一篇隨筆,包含下述三個環節的所有要求。 第一部分 調研, 評測 下載軟件並使用起來,描述最簡
第二階段:2.商業需求分析及BRD:4.產品需求分析總結
總結 ima src 引導 產品需求 都是 篩選 img alt 產品的需求篩選 戰略定位要考慮公司的戰略問題。產品定位要分階段,各個階段的需求不同。 其實現在需求分析跟篩選都是非常快的。 不把需要當成需求,意思就是不要用戶說需要什麽就是什麽,用戶需要引導。
第二階段:2.商業需求分析及BRD:1.產品需求管理
管理 excel 有時 商業 重要 整理 需求分析 圖片 采集 產品經理需要投入大量的時間在需求方面的工作。 一張圖看出需求多麽重要。各個方面的人物對需求的誤解導致的後果。 首先收集需求 需求采集 可以用excel收集數據並整理 備註信息也很重要 有時候要跟提出人
第二階段:2.商業需求分析及BRD:5.商業需求文檔1
價值 產品介紹 fsd 計劃 線路 資源 結構 決策 9.png 三大文檔 FSD一般包含在PRD 1.BRD一般是去向決策層匯報 2.產品介紹的各項是可選的 不是必備的 產品線路圖就是roodmap。團隊一般是偏技術的團隊。 BRD案例。 痛點。定性的描述。不會非常
誰說菜鳥不會資料分析(入門篇)----- 學習筆記2(結構為王:確定分析思路 4P 5W2H )
1、資料分析方法論 確定分析思路需要以營銷、管理等理論為指導,把這些跟資料分析相關的營銷、管理等理論統稱為資料分析方法論。 資料分析方法論主要用來指導資料分析師進行一次完整的資料分析,更多的是指資料分析思路,如從哪方面開展資料分析?各方面包含什麼內容和指標。 資料分析方法論主要
中國電信物聯網平臺使用2: DOME程式分析
"墨子號NB-IOT開發板"提供的dome: 程式只要分為延時,定時器,串列埠通訊…… 工程檔案在:…\STM32L1xx_StdPeriph_Lib_V1.3.1\Project\Test\MDK-ARM 程式初始化部分: delay_init();---------提供系統的延時功能 L
C++解析(2):進化後的 const 分析
0.目錄 1.C語言中的const 2.C++中的const 3.對比 3.1 C語言與C++中的const 3.2 C++中的const與巨集定義 4.小結 1.C語言中的const const修飾的變數是只讀的,本質還是變數 const修飾的區域性變數在棧上分配空間
誰說菜鳥不會資料分析(工具篇)----- 學習筆記2(結構為王:確定分析思路)
1、資料分析方法論 確定分析思路需要以營銷、管理等理論為指導,把這些跟資料分析相關的營銷、管理等理論統稱為資料分析方法論。 資料分析方法論主要用來指導資料分析師進行一次完整的資料分析,更多的是指資料分析思路,如從哪方面開展資料分析?各方面包含什麼內容和指標。 資料分析方
QIIME 2:可重複、互動和擴充套件的微生物組資料分析流程
文章目錄 QIIME2:可重複、可互動、適用範圍廣和可擴充套件的微生物組資料科學 摘要 正文 圖1. 互動式視覺化工具 圖2. 迭代記錄資料來源確保分析可重複 程式碼可用 線上方法
無鎖執行緒通訊(2):例程與分析
首先,我們來看一個例子。 1 // 互動通道“沒有貨”狀態 2 #define COMMUNICATIONCHANNEL_STATE_THINGSNOTEXISTS 0 3 // 互動通道“有貨”狀態 4 #define COMMUNICATIONCHANNEL_STATE_