主要內容:ViewTreeObserver 是被用來註冊監聽視圖樹的觀察者,在視圖樹發生全局改變時將收到通知。本文從 ViewTreeObserver 源碼出發,帶你剖析 ViewTreeObserver 的設計及使用,並間接體會觀察者模式、Android消息傳遞機制在其中的使用。
這兩天看代碼看到了 ViewTreeObserver ,以前有接觸過,但一直不太其到底在表達什麼。此次既然又碰到了,那就乾脆研究一下吧。因而我開始以關鍵字「ViewTreeObserver」 Google 相關內容,結果發現找到的內容都差很少,更有甚者通篇直接翻譯api,驚呆了!真的一點都不誇張,不相信的能夠本身搜索試試看…
本系列分爲上下兩篇,本篇較爲基礎,主要介紹 ViewTreeObserver 的基礎信息,以及說一下觀察者模式,至於消息傳遞以及實戰等更多內容將在下篇介紹。
1. 分開理解 ViewTreeObserver
ViewTreeObserver,拆開來理解就是 ViewTree 和 Observer。
ViewTree 就是咱們常說的視圖樹,在Android中,全部視圖都是由View及View的子類構成,ViewGroup 也是View的子類,它能夠裝載View或者ViewGroup,這樣,一層層嵌套,就有了視圖樹的概念。給一張圖感覺一下:android
視圖樹
Observer 即觀察者的意思,其對應的觀察者模式是軟件設計模式的一種,在許多編程語言中被普遍運用。其核心在於:一個目標對象,咱們稱之爲被觀察者(Observable),管理着全部依附於它的觀察者(Observers),當被觀察者發生某種改變時(稱爲事件),被觀察者調用對該事件感興趣的觀察者所提供的方法,主動通知觀察者。
總結起來就是三要素:觀察者,被觀察者,事件,圖示以下,圖畫的有點虛。編程
觀察者和被觀察者
至於在 ViewTreeObserver 中,觀察者模式是如何工做的,須要留到後面再說了,由於涉及到 View 的 measure、layout 和 draw 等過程。等不及的能夠本身看一下,給點提示:看 ViewRootImpl 類。
2. ViewTreeObserver 概念
分別介紹 ViewTree 和 Observer 以後,咱們就不難理解 ViewTreeObserver 的概念了。在這裏,ViewTree 即爲被觀察者(也能夠是單個View),ViewTreeObserver 就是觀察者,ViewTreeObserver 對 ViewTree 註冊監聽(觀察它),當 ViewTree 發生某種變化時,將調用 ViewTreeObserver 的相關方法,通知其這一改變。咱們要作的就是覆寫這一方法,添加本身的邏輯。
來看一下官方文檔的註釋說明:
ViewTreeObserver 是被用來註冊監聽視圖樹的觀察者,在視圖樹發生全局改變時將收到通知。這種全局事件包括但不限於:整個視圖樹的佈局發生改變、在視圖開始繪製以前、視圖觸摸模式改變時…
3. 獲取 ViewTreeObserver 對象
瞭解了 ViewTreeObserver 以後,接下來講說如何獲取 ViewTreeObserver 對象。我想大多數人會想到 new ViewTreeObserver(),由於這個咱們最擅長了。
可是,ViewTreeObserver 的構造方法明確聲明瞭:This constructor should not be called。也就是咱們無法調用,當咱們嘗試這麼作時,IDE 會提示:
'ViewTreeObserver()' is not public in 'android.view.ViewTreeObserver'.Cannot be accessed from outside package
根據 ViewTreeObserver 類的註釋可知,咱們只能經過 View 的 getViewTreeObserver() 方法獲取 ViewTreeObserver 對象,那麼咱們看一下 getViewTreeObserver() 方法的源碼:設計模式
getViewTreeObserver
先介紹一下方法中的 AttachInfo,官方文檔如此註釋說明:
A set of information given to a view when it is attached to its parent
意思是:當這個 View 被附着到父窗口時,將會得到這一組信息。說的好抽象啊,仍是本身這組信息都有啥吧。
AttachInfo 是 View 類的內部類,找到這個類,瀏覽一遍,發現其含了一個 ViewTreeObserver 對象,以及該 View 所處的窗口(Window)、設備(Display)、根視圖(rootView)等信息,信息量仍是蠻大的,感興趣的能夠本身瞭解下,咱們目前只關心這個 ViewTreeObserver 對象。
下面分析方法的邏輯。這個方法首先判斷 View 所持有的 mAttachInfo ,當 mAttachInfo 不爲空時,直接返回 mAttachInfo 中的 ViewTreeObserver 對象;不然去判斷 View 類的 ViewTreeObserver 對象 mFloatingTreeObserver,若 mFloatingTreeObserver 爲空,則建立該對象,並返回。
對於 mFloatingTreeObserver,官方註釋爲:
Special tree observer used when mAttachInfo is null.
很明顯,這是一個特殊的視圖樹觀察者對象,只有當 mAttachInfo 爲空時纔會被使用。
至此,咱們成功的獲取了 ViewTreeObserver 對象。
4. 確保 ViewTreeObserver 可用
在前面,咱們成功獲取了 ViewTreeObserver 對象,當咱們使用該 對象調用 addOnXxxListener 方法監聽 View 的某個狀態時,該方法老是首先調用 checkIsAlive() 方法,檢測 View 的 ViewTreeObserver 對象是否存活(可用)。
爲何要先去檢測呢?官方文檔給出的解釋是:經過 View 的 getViewTreeObserver() 方法返回的 ViewTreeObserver ,在 View 的生命週期中不能保證始終有效。
既然我如此,那麼經過源碼咱們看一下 checkIsAlive() 都作了什麼:api
checkIsAlive
邏輯仍是很簡單的:若是 View 的 ViewTreeObserver 對象不可用,將拋出 IllegalStateException (非法狀態異常),並提示咱們 從新調用 View 的 getViewTreeObserver() 方法獲取對象。
可是,咱們能不能在調用 addOnXxxListener 以前,可否檢測當前 View 的 ViewTreeObserver 對象是否可用呢,總不能每次等異常了才發現要去從新獲取把?答案是確定的!
ViewTreeObserver 爲咱們提供了 isAlive() 方法,邏輯很簡單,就一句代碼「return mAlive」,mAlive 就是在 checkIsAlive() 方法中所判斷的變量。該變量標記當前 View 的 ViewTreeObserver 對象是否可用。
最後,翻譯官方文檔的註釋,來總結如何確保 ViewTreeObserver 可用:
當 ViewTreeObserver 不可用時,調用 isAlive() 方法之外的任何其餘方法,都將拋出異常。因此,若是 View 對 ViewTreeObserver 持有長時間引用,那麼其應該在調用 ViewTreeObserver 對象的任何其餘方法以前,確保經過 isAlive() 的返回值檢查 ViewTreeObserver 的狀態是否可用。
5. 結尾
至此,有關 ViewTreeObserver 的基礎只是介紹就到這兒了,相信你必定會以爲沒看過癮,由於本篇只是介紹了 ViewTreeObserver 的概念、如何獲取View實例,以及如何避免 ViewTreeObserver 對象爲空,我也覺的說的有點簡單了。可是,當你發現這些網上都沒有,須要靠本身讀源碼和註釋去了解時,就不是那麼簡單了。
下篇預告:ViewTreeObserver 的 API 介紹、觀察者模式是如何起做用的、View 涉及的消息傳遞機制 以及 ViewTreeObserver 的使用等,通通放出來。請耐心等候,這期間不妨本身去看看源碼。
最後,感謝你耐心看完,看完以後有任何問題,歡迎隨時交流。
編程語言