Android Architecture Components 源碼分析 第三篇

本文已授權(quán)我就是馬云飛公眾號獨家發(fā)布聊闯。

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

Android Architecture Components 源碼分析系列文章

  1. Android Architecture Components 第一篇拴泌,介紹生命周期的感知魏身。
  2. Android Architecture Components 第二篇,介紹ViewModel的控制蚪腐。
  3. Android Architecture Components 第三篇箭昵,介紹LiveDate和LifeRegistry的協(xié)同操作。

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

簡單案例

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

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

在ViewModel中就是擁有一個成員變量鼻忠,加上對應(yīng)的get方法涵但,修改數(shù)據(jù)的時候直接使用setValue更新,這樣就會彈出一個Toast。

使用起來并不難贤笆,但我們的目的是了解如何實現(xiàn)的蝇棉。

案例分析

關(guān)于上文的例子,從三個部分開始分析芥永,一是添加觀察者的時候篡殷,二是生命周期的控制,三是設(shè)置數(shù)據(jù)的時候埋涧。

添加觀察者

  1. 先判斷一下LifecycleRegistry當(dāng)前的狀態(tài)板辽,如果是DESTORYED的話,就直接返回棘催。
  2. 之后是將LifecycleOwner和創(chuàng)建Observer封裝到LifecycleBoundObserver中劲弦。
  3. 從當(dāng)前的Oberver集合中查找沒有傳入的Observer對應(yīng)的包裝類,如果有則返回醇坝,沒有則添加邑跪。
  4. LifecycleRegistry添加包裝之后的LifecycleBoundObserver觀察者。
  5. 更新下當(dāng)前的包裝類的狀態(tài)呼猪。

這里需要理解并記住的是LifecycleBoundObserver是一個擁有真正回調(diào)Observer和LifecycleOwner的封裝類画畅。

在LifecycleRegistry中添加觀察者,這個LifecycleRegistry是在Activity/Fragment中創(chuàng)建的成員變量宋距。

  1. 確定初始時LifecycleBoundObserverd的狀態(tài)轴踱,這里大部分的情況都是INITIALIZED,除非把之前的observe寫在onDestory中谚赎,不過估計一般沒人這么寫淫僻。
  2. 將傳入的LifecycleBoundObserver和確定的狀態(tài)封裝到一個statefulObserver。在這個過程中會對observer進(jìn)行一定轉(zhuǎn)化壶唤,將其改變成另一種LifecycleObserver雳灵,然后再使用的時候會通過反射去調(diào)到實際需要的方法。
  3. 將封裝過的statefulObserver和傳入的observer添加到當(dāng)前的一個map中進(jìn)行保存闸盔,如果之前已經(jīng)添加過的話悯辙,就直接返回舊的,沒有的話再放入蕾殴,返回null笑撞。
  4. 判斷是否可以重入,來決定是否進(jìn)行同步,這里的parentState暫時先不考慮钓觉,等最后的時候再分析茴肥。
  5. 其中while循環(huán)的部分是為了修改剛添加進(jìn)去的ObseverWithState中state的狀態(tài)。
  6. sync方法是事件傳遞的關(guān)鍵荡灾,在之后也會用到瓤狐,就先不分析瞬铸。

接下來看一下當(dāng)生命周期變化的時候會發(fā)生什么?

生命周期改變

根據(jù)第一篇文章中我們可以知道當(dāng)應(yīng)用的生命周期變化的時候础锐,會發(fā)送對應(yīng)的生命周期事件到LifecycleRegistry的handleLifecycleEvent方法中進(jìn)行處理嗓节,這里先簡單的分析下邏輯。

首先設(shè)置當(dāng)前的LifecycleRegistry中的mState值皆警,之后執(zhí)行sync方法

這里先判斷一下是否可以進(jìn)行同步拦宣,判斷的條件是當(dāng)前map中的oberver數(shù)量和狀態(tài),之后會根據(jù)當(dāng)前的mObserverMap中保存的observer的狀態(tài)和當(dāng)前的Registry的狀態(tài)進(jìn)行比較信姓,來決定是進(jìn)行正推計算還是反推計算鸵隧。先以正推計算為例:

把當(dāng)前的mObserverMap中的數(shù)據(jù)進(jìn)行迭代,判斷狀態(tài)之后執(zhí)行observer.dispatchEvent()方法意推,來同步Observer

這里會先設(shè)置當(dāng)前的Observer的狀態(tài)豆瘫,之后會調(diào)用Observer的onStateChanged方法,這個方法會經(jīng)過一系列的變化菊值,通過反射外驱,最終調(diào)到LiveData中的LifecycleBoundObserver的onStateChage()方法

這兩個方法最主要的作用就是判斷當(dāng)前的LifecycleOwner是否是active狀態(tài)。如果是active狀態(tài)的話就刷新數(shù)據(jù)腻窒。

數(shù)據(jù)更新

上面正好講到刷新數(shù)據(jù)昵宇,我們來繼續(xù)說一下當(dāng)setvalue的時候發(fā)生了什么:

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

這里的關(guān)鍵函數(shù)就是considerNotify,如果是通過setValue方法進(jìn)行更新的話定页,會更新所有的observer,如果是通過handleLifecycleEvent方法進(jìn)行更新的話趟薄,那么只會更改當(dāng)前的observer绽诚。

首先會先檢查當(dāng)前的observer的active,之后會檢查observer的owner的狀態(tài)是否是可用的典徊,再判斷當(dāng)前的版本。最后進(jìn)行更新數(shù)據(jù)恩够。

小結(jié)

到這里其實整體的生命周期事件的觀察和傳遞卒落,同步和更新,修改數(shù)據(jù)蜂桶,都已經(jīng)簡單的介紹完畢了儡毕,單單拿出來一個部分其實并不難理解,主要需要明白并記住的就是LifecycleRigestry的mState扑媚、Event腰湾、ObserverWithState的mState和LifecycleBoundObserver的active。事件的來源只有一種就是handleLifecycleEvent疆股,最終的目的地就是為了修改ObserverWithState的mState和LifecycleBoundObserver的active费坊。

整體流程分析

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

這個是我自己梳理的整體的事件流程和刷新的圖永毅。根據(jù)這個圖來介紹下執(zhí)行的流程把跨。

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

  2. Activity啟動,傳遞過來第一個生命周期事件ON_CREATE浸间,通過getStateAfter計算之后的State為CREATED賦值給RS太雨,判斷狀態(tài)決定執(zhí)行正推計算,OS的當(dāng)前值為INITIALIZED魁蒜,更改LifecycleBoundObserver的active(下文簡稱active)值為false囊扳。OS修改為CREATED。

  3. 事件ON_START兜看,RS為STARTED锥咸,正推計算,OS當(dāng)前值為CREATED细移,更改active為true搏予。OS修改為STARTED。

  4. 事件ON_RESUME弧轧,RS為RESUMED雪侥,正推計算,OS當(dāng)前值為STARTED精绎,更改active為true速缨。OS修改為RESUMED。

  5. 事件ON_PAUSE代乃,RS為STARTED旬牲,反推計算,OS當(dāng)前值為STARTED搁吓,更改active為true原茅。OS修改為STARTED。

  6. 事件ON_STOP堕仔,RS為CREATED擂橘,反推計算,OS當(dāng)前值為CREATED贮预,更改active為false贝室。OS修改為CREATED契讲。

  7. 事件ON_DESTROY,RS為DESTROYED滑频,反推計算捡偏,OS當(dāng)前值為DESTROYED,更改active為false峡迷。OS修改為DESTROYED银伟。

整體事件流程就是這樣,通過感知Activity/Fragment的生命周期绘搞,然后分發(fā)到LifecycleRegistry中進(jìn)行處理彤避,根據(jù)當(dāng)前的狀態(tài)來修改保存的ObserverWithState的mState,然后修改LifecycleBoundObserver的active決定數(shù)據(jù)是否可以更新夯辖。

上面的狀態(tài)都是作者根據(jù)最開始的案例斷點調(diào)試得出的結(jié)論琉预,值得注意的就是因為有Application也就是ProcessLifecycleOwner的干擾,調(diào)試的時候要區(qū)分好LifeRegistry蒿褂,第二個注意的就是mState的值圆米,因為有兩個mState,經(jīng)常會需要進(jìn)行比較啄栓,來決定同步娄帖。

總結(jié)

至此,整個Android Architecture Components架構(gòu)中所有的源碼都過了一遍了昙楚, 主要的難點就是在handleLifecycleEvent()和Sync()兩個方法近速。總體的分析下整個架構(gòu):

個人認(rèn)為主要分為三個部分:

第一部分:生命周期的感知包括系統(tǒng)生命周期的感知堪旧。其中有使用的類和技巧有削葱,通過注冊ContenProvider進(jìn)行項目的初始化,通過添加Fragment來獲取宿主的生命周期崎场。通過給Application和Activity添加生命周期的回調(diào)佩耳,來進(jìn)行Fragment的初始化和生命周期的感知遂蛀。

相關(guān)的類包括:
LifecycleRuntimeTrojanProvider 用于進(jìn)行初始化init操作 谭跨、
LifecycleDispatcher 用于進(jìn)行生命周期分發(fā)處理
ProcessLifecycleOwner 應(yīng)用生命周期控制 ,李滴、
ReportFragment 添加的Fragment 用于感知宿主生命周期 螃宙。

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

相關(guān)的類包括:
ViewModel 芹助、
ViewModelProvider ViewModel的提供者 堂湖、
ViewModelStore 用于保存ViewModel闲先、
HolderFragment 添加的Fragment 用于感知宿主生命周期等。

第三部分:LiveData和LifecycleRegistry的協(xié)同操作无蜂。這里使用了兩個枚舉對象來概括整體的生命周期伺糠,通過Event的傳遞來改變當(dāng)前的Lifecycyle的狀態(tài),同時更新當(dāng)前的Observer是否處于活動狀態(tài)斥季。個人認(rèn)為整個項目中的關(guān)于Observer的三個封裝類是整個項目的骨架训桶,State和Event就是流動血液,而HandleLifecycleEvent和Sync兩個方法就是整個項目的靈魂酣倾。

相關(guān)的類包括:
LiveData 數(shù)據(jù)模型 舵揭、
LifecycleOwner 生命周期持有者
LifecycleRegistry 用于控制生命周期 躁锡、
ObserverWithState 保存Observer和對應(yīng)的狀態(tài) 午绳、
LifecycleBoundObserver 保存Observer和LifecycleOwner
ReflectiveGenericLifecycleObserver 反射調(diào)用的相關(guān)類映之。

學(xué)習(xí)收獲

這不是我第一次去深入的研究系統(tǒng)的源碼了箱叁,不過每一次看源代碼真的都能帶來新的收獲和想法。在學(xué)習(xí)AAC的過程中惕医,最大的收獲感覺還是對AAC項目的熟悉耕漱,能夠清楚的知道每一個類,每一個方法抬伺,每一個成員變量的作用螟够,是用來做什么的,什么起作用峡钓。當(dāng)我看到它們的類名就能夠知道他們是做什么的妓笙,這種熟悉感,我覺得是最大的收獲能岩。其次是在研究源碼過程中一些心得體會寞宫,遇到難度高的地方的時候適當(dāng)?shù)姆潘桑娴臅兄诮鉀Q問題拉鹃,我這里有好幾個關(guān)鍵點都是我下樓散步的時候想到的為什么辈赋。

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

  1. 會使用,能夠?qū)懘a
  2. 知道原理坝辫,了解源代碼是什么實現(xiàn)的篷就,知道每一個部分的原理,功用近忙。
  3. 能夠修改竭业,在原有的基礎(chǔ)上進(jìn)行修改智润,使其變得更優(yōu)或者更適用于自己。

目前在學(xué)習(xí)第三方框架的時候未辆,都在遵循著三點做鹰,爭取都能夠達(dá)到第二層次,部分簡單的項目可以實現(xiàn)第三層次鼎姐。這好比練武功钾麸,從登堂入室,再到爛熟于心炕桨,再到推陳出新饭尝。

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末钥平,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子姊途,更是在濱河造成了極大的恐慌涉瘾,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捷兰,死亡現(xiàn)場離奇詭異立叛,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)贡茅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門秘蛇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人顶考,你說我怎么就攤上這事赁还。” “怎么了驹沿?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵艘策,是天一觀的道長。 經(jīng)常有香客問我渊季,道長朋蔫,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任梭域,我火速辦了婚禮斑举,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘病涨。我一直安慰自己,他們只是感情好璧坟,可當(dāng)我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布既穆。 她就那樣靜靜地躺著赎懦,像睡著了一般。 火紅的嫁衣襯著肌膚如雪幻工。 梳的紋絲不亂的頭發(fā)上励两,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機(jī)與錄音囊颅,去河邊找鬼当悔。 笑死,一個胖子當(dāng)著我的面吹牛踢代,可吹牛的內(nèi)容都是我干的盲憎。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼胳挎,長吁一口氣:“原來是場噩夢啊……” “哼饼疙!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起慕爬,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤窑眯,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后医窿,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體磅甩,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年姥卢,在試婚紗的時候發(fā)現(xiàn)自己被綠了更胖。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡隔显,死狀恐怖却妨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情括眠,我是刑警寧澤彪标,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站掷豺,受9級特大地震影響捞烟,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜当船,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一题画、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧德频,春花似錦苍息、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽表谊。三九已至,卻和暖如春盖喷,著一層夾襖步出監(jiān)牢的瞬間爆办,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工课梳, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留距辆,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓暮刃,卻偏偏與公主長得像跨算,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子沾歪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容