Android Architecture Components 源碼分析 第三篇

本文已授權我就是馬云飛公眾號獨家發布。

說是源碼分析有點,其實就是簡單的根據源碼梳理一遍整體的LiveData,ViewModel和Lifecycle各個部分是如何工作的,由于本人水平有限,如果文中有錯誤的地方,歡迎指正。

Android Architecture Components 源碼分析系列文章

  1. Android Architecture Components 第一篇,介紹生命周期的感知。
  2. Android Architecture Components 第二篇,介紹ViewModel的控制。
  3. Android Architecture Components 第三篇,介紹LiveDate和LifeRegistry的協同操作。

這個是Android Architecture Components(簡稱AAC)的第三篇,之前的兩篇 文章分別介紹了Lifecycle和ViewModel的生命周期,這篇主要講的就是最開始提出的第三個問題LiveData數據的控制。

簡單案例

先列舉一個簡單的例子,看看如何使用的

在ViewModel中有LiveData的成員變量,然后添加一個觀察者。在ViewModel中

在ViewModel中就是擁有一個成員變量,加上對應的get方法,修改數據的時候直接使用setValue更新,這樣就會彈出一個Toast。

使用起來并不難,但我們的目的是了解如何實現的。

案例分析

關于上文的例子,從三個部分開始分析,一是添加觀察者的時候,二是生命周期的控制,三是設置數據的時候。

添加觀察者

  1. 先判斷一下LifecycleRegistry當前的狀態,如果是DESTORYED的話,就直接返回。
  2. 之后是將LifecycleOwner和創建Observer封裝到LifecycleBoundObserver中。
  3. 從當前的Oberver集合中查找沒有傳入的Observer對應的包裝類,如果有則返回,沒有則添加。
  4. LifecycleRegistry添加包裝之后的LifecycleBoundObserver觀察者。
  5. 更新下當前的包裝類的狀態。

這里需要理解并記住的是LifecycleBoundObserver是一個擁有真正回調Observer和LifecycleOwner的封裝類。

在LifecycleRegistry中添加觀察者,這個LifecycleRegistry是在Activity/Fragment中創建的成員變量。

  1. 確定初始時LifecycleBoundObserverd的狀態,這里大部分的情況都是INITIALIZED,除非把之前的observe寫在onDestory中,不過估計一般沒人這么寫。
  2. 將傳入的LifecycleBoundObserver和確定的狀態封裝到一個statefulObserver。在這個過程中會對observer進行一定轉化,將其改變成另一種LifecycleObserver,然后再使用的時候會通過反射去調到實際需要的方法。
  3. 將封裝過的statefulObserver和傳入的observer添加到當前的一個map中進行保存,如果之前已經添加過的話,就直接返回舊的,沒有的話再放入,返回null。
  4. 判斷是否可以重入,來決定是否進行同步,這里的parentState暫時先不考慮,等最后的時候再分析。
  5. 其中while循環的部分是為了修改剛添加進去的ObseverWithState中state的狀態。
  6. sync方法是事件傳遞的關鍵,在之后也會用到,就先不分析。

接下來看一下當生命周期變化的時候會發生什么?

生命周期改變

根據第一篇文章中我們可以知道當應用的生命周期變化的時候,會發送對應的生命周期事件到LifecycleRegistry的handleLifecycleEvent方法中進行處理,這里先簡單的分析下邏輯。

首先設置當前的LifecycleRegistry中的mState值,之后執行sync方法

這里先判斷一下是否可以進行同步,判斷的條件是當前map中的oberver數量和狀態,之后會根據當前的mObserverMap中保存的observer的狀態和當前的Registry的狀態進行比較,來決定是進行正推計算還是反推計算。先以正推計算為例:

把當前的mObserverMap中的數據進行迭代,判斷狀態之后執行observer.dispatchEvent()方法,來同步Observer

這里會先設置當前的Observer的狀態,之后會調用Observer的onStateChanged方法,這個方法會經過一系列的變化,通過反射,最終調到LiveData中的LifecycleBoundObserver的onStateChage()方法

這兩個方法最主要的作用就是判斷當前的LifecycleOwner是否是active狀態。如果是active狀態的話就刷新數據。

數據更新

上面正好講到刷新數據,我們來繼續說一下當setvalue的時候發生了什么:

可以看到將成員變量mData賦值 ,之后也是調用了相同的dispatchingValue方法

這里的關鍵函數就是considerNotify,如果是通過setValue方法進行更新的話,會更新所有的observer,如果是通過handleLifecycleEvent方法進行更新的話,那么只會更改當前的observer。

首先會先檢查當前的observer的active,之后會檢查observer的owner的狀態是否是可用的,再判斷當前的版本。最后進行更新數據。

小結

到這里其實整體的生命周期事件的觀察和傳遞,同步和更新,修改數據,都已經簡單的介紹完畢了,單單拿出來一個部分其實并不難理解,主要需要明白并記住的就是LifecycleRigestry的mState、Event、ObserverWithState的mState和LifecycleBoundObserver的active。事件的來源只有一種就是handleLifecycleEvent,最終的目的地就是為了修改ObserverWithState的mState和LifecycleBoundObserver的active。

整體流程分析

每一個小部分的功能都有所了解的之后,讓我們嘗試下梳理最上面的案例中整個事件的傳遞。這里添加訂閱者是在onCreate方法中。先上個我自己畫的圖,方便理解。

這個是我自己梳理的整體的事件流程和刷新的圖。根據這個圖來介紹下執行的流程。

  1. 由于上面的案例是在onCreate中訂閱的,那么最開始先執行的應該是addObserver,這個時候會把LifecycleRegistry的mState(下文簡稱RS)置為INITIALIZED。并向observerMap中添加封裝過的ObserverWithState,其中的mState(下文簡稱OS)為INITIALIZED。不執行同步方法。

  2. Activity啟動,傳遞過來第一個生命周期事件ON_CREATE,通過getStateAfter計算之后的State為CREATED賦值給RS,判斷狀態決定執行正推計算,OS的當前值為INITIALIZED,更改LifecycleBoundObserver的active(下文簡稱active)值為false。OS修改為CREATED。

  3. 事件ON_START,RS為STARTED,正推計算,OS當前值為CREATED,更改active為true。OS修改為STARTED。

  4. 事件ON_RESUME,RS為RESUMED,正推計算,OS當前值為STARTED,更改active為true。OS修改為RESUMED。

  5. 事件ON_PAUSE,RS為STARTED,反推計算,OS當前值為STARTED,更改active為true。OS修改為STARTED。

  6. 事件ON_STOP,RS為CREATED,反推計算,OS當前值為CREATED,更改active為false。OS修改為CREATED。

  7. 事件ON_DESTROY,RS為DESTROYED,反推計算,OS當前值為DESTROYED,更改active為false。OS修改為DESTROYED。

整體事件流程就是這樣,通過感知Activity/Fragment的生命周期,然后分發到LifecycleRegistry中進行處理,根據當前的狀態來修改保存的ObserverWithState的mState,然后修改LifecycleBoundObserver的active決定數據是否可以更新。

上面的狀態都是作者根據最開始的案例斷點調試得出的結論,值得注意的就是因為有Application也就是ProcessLifecycleOwner的干擾,調試的時候要區分好LifeRegistry,第二個注意的就是mState的值,因為有兩個mState,經常會需要進行比較,來決定同步。

總結

至此,整個Android Architecture Components架構中所有的源碼都過了一遍了, 主要的難點就是在handleLifecycleEvent()和Sync()兩個方法??傮w的分析下整個架構:

個人認為主要分為三個部分:

第一部分:生命周期的感知包括系統生命周期的感知。其中有使用的類和技巧有,通過注冊ContenProvider進行項目的初始化,通過添加Fragment來獲取宿主的生命周期。通過給Application和Activity添加生命周期的回調,來進行Fragment的初始化和生命周期的感知。

相關的類包括:
LifecycleRuntimeTrojanProvider 用于進行初始化init操作
LifecycleDispatcher 用于進行生命周期分發處理
ProcessLifecycleOwner 應用生命周期控制 ,、
ReportFragment 添加的Fragment 用于感知宿主生命周期 。

第二部分:ViewModel生命周期的控制。同樣使用了添加Fragment來感知宿主的生命周期,通過一個HoldFragment來持有一個ViewModelStore保存當前宿主的所有ViewModel,通過工廠模式反射獲得ViewModel對象。

相關的類包括:
ViewModel 、
ViewModelProvider ViewModel的提供者 、
ViewModelStore 用于保存ViewModel、
HolderFragment 添加的Fragment 用于感知宿主生命周期等。

第三部分:LiveData和LifecycleRegistry的協同操作。這里使用了兩個枚舉對象來概括整體的生命周期,通過Event的傳遞來改變當前的Lifecycyle的狀態,同時更新當前的Observer是否處于活動狀態。個人認為整個項目中的關于Observer的三個封裝類是整個項目的骨架,State和Event就是流動血液,而HandleLifecycleEvent和Sync兩個方法就是整個項目的靈魂。

相關的類包括:
LiveData 數據模型 、
LifecycleOwner 生命周期持有者 、
LifecycleRegistry 用于控制生命周期 、
ObserverWithState 保存Observer和對應的狀態
LifecycleBoundObserver 保存Observer和LifecycleOwner
ReflectiveGenericLifecycleObserver 反射調用的相關類。

學習收獲

這不是我第一次去深入的研究系統的源碼了,不過每一次看源代碼真的都能帶來新的收獲和想法。在學習AAC的過程中,最大的收獲感覺還是對AAC項目的熟悉,能夠清楚的知道每一個類,每一個方法,每一個成員變量的作用,是用來做什么的,什么起作用。當我看到它們的類名就能夠知道他們是做什么的,這種熟悉感,我覺得是最大的收獲。其次是在研究源碼過程中一些心得體會,遇到難度高的地方的時候適當的放松,真的會有助于解決問題,我這里有好幾個關鍵點都是我下樓散步的時候想到的為什么。

最后想要說的就是對于知識的渴望程度,或者說對于知識的了解程度,我覺得這種概念適用于所有領域,以AAC這個框架為例

  1. 會使用,能夠寫代碼
  2. 知道原理,了解源代碼是什么實現的,知道每一個部分的原理,功用。
  3. 能夠修改,在原有的基礎上進行修改,使其變得更優或者更適用于自己。

目前在學習第三方框架的時候,都在遵循著三點,爭取都能夠達到第二層次,部分簡單的項目可以實現第三層次。這好比練武功,從登堂入室,再到爛熟于心,再到推陳出新。

會用的人太多,而知道為什么的人太少。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容