目錄介紹
- 01.LiveData是什么東西
- 02.使用LiveData的優勢
- 03.使用LiveData的步驟
- 04.簡單使用LiveData
- 05.observe()和observerForever()
- 06.LiveData原理介紹
- 07.observe訂閱源碼分析
- 08.setValue發送源碼分析
- 09.observeForever源碼
- 10.LiveData源碼總結
00.使用LiveData實現bus事件總線
- 利用LiveData實現事件總線,替代EventBus。充分利用了生命周期感知功能,可以在activities, fragments, 或者 services生命周期是活躍狀態時更新這些組件。支持發送普通事件,也可以發送粘性事件;還可以發送延遲消息,以及輪訓延遲消息等等。
- https://github.com/yangchong211/YCLiveDataBus
01.LiveData是什么東西
- 基於觀察者模式
- LiveData是一種持有可被觀察數據的類。LiveData需要一個觀察者對象,一般是Observer類的具體實現。當觀察者的生命周期處於STARTED或RESUMED狀態時,LiveData會通知觀察者數據變化。
- 感知生命周期
- 和其他可被觀察的類不同的是,LiveData是有生命周期感知能力的,這意味着它可以在activities, fragments, 或者 services生命周期是活躍狀態時更新這些組件。那么什么是活躍狀態呢?就是STARTED和RESUMED就是活躍狀態,只有在這兩個狀態下LiveData是會通知數據變化的。
- 自動解除數據訂閱
- 要想使用LiveData(或者這種有可被觀察數據能力的類)就必須配合實現了LifecycleOwner的對象使用。在這種情況下,當對應的生命周期對象DESTORY時,才能移除觀察者。這對Activity或者Fragment來說顯得尤為重要,因為他們可以在生命周期結束的時候立刻解除對數據的訂閱,從而避免內存泄漏等問題。
02.使用LiveData的優勢
2.1 具有很明顯的優點
- UI和實時數據保持一致
- 因為LiveData采用的是觀察者模式,這樣一來就可以在數據發生改變時獲得通知,更新UI。
- 不會發生內存泄露
- 觀察者被綁定到組件的生命周期上,當被綁定的組件銷毀(onDestroy)時,觀察者會立刻自動清理自身的數據。
- 不會再產生由於Activity處於stop狀態而引起的崩潰
- 例如:當Activity處於后台狀態時,是不會收到LiveData的任何事件的。
- 不需要再解決生命周期帶來的問題
- LiveData可以感知被綁定的組件的生命周期,只有在活躍狀態才會通知數據變化。
- 實時數據刷新
- 當組件處於活躍狀態或者從不活躍狀態到活躍狀態時總是能收到最新的數據
- 解決Configuration Change問題
- 在屏幕發生旋轉或者被回收再次啟動,立刻就能收到最新的數據。
- 數據共享
- 如果對應的LiveData是單例的話,就能在app的組件間分享數據。這部分詳細的信息可以參考繼承LiveData
2.2 細節點補充
- 組件和數據相關的內容能實時更新,組件在前台的時候能夠實時收到數據改變的通知,當組件從后台到前台來時,LiveData能夠將最新的數據通知組件,因此保證了組件中和數據相關的內容能夠實時更新。
- 如果橫豎屏切換(configuration change)時,不需要額外的處理來保存數據,當屏幕方向變化時,組件會被recreate,然而系統並不能保證你的數據能夠被恢復的。當我們采用LiveData保存數據時,因為數據和組件分離了。當組件被recreate,數據還是存在LiveData中,並不會被銷毀。
03.使用LiveData的步驟
- 創建一個持有某種數據類型的LiveData (通常是在ViewModel中)
- 創建一個定義了onChange()方法的觀察者。這個方法是控制LiveData中數據發生變化時,采取什么措施 (比如更新界面)。通常是在UI Controller (Activity/Fragment) 中創建這個觀察者。
- 通過 observe()方法連接觀察者和LiveData。observe()方法需要攜帶一個LifecycleOwner類。這樣就可以讓觀察者訂閱LiveData中的數據,實現實時更新。
04.簡單使用LiveData
4.1 單獨使用LiveData
- 舉一個最簡單的案例代碼:
- 那么上面這一段代碼大概是什么意思呢?
- 首先創建一個 MutableLiveData(LiveData是抽象類)對象 ,通過 observe 方法可以訂閱修改數據的通知,通過 postValue()或者 setValue() 方法發送事件更新數據,已經訂閱的 Observer 能夠得到數據更改的通知,就會回調 onChanged() 方法。
4.2 使用LiveData配合ViewModel
- LiveData是一個數據的包裝。具體的包裝對象可以是任何數據,包括集合。它是一個抽象類,首先先創建一個類實現LiveData。代碼如下所示:
- 創建一個觀察的對象,觀察LiveData中的數據。目前在組件的onCreate()方法中開始觀察數據,代碼如下所示:
- 思考下,可以在onResume()中調用么,個人覺得不太好。因為系統會多次調用onResume()方法。
- 然后去創建更新對象數據內容的對象。如何去更新那個文本中的數據呢?代碼如下所示:
- 想要在UI Controller中改變LiveData中的值呢?(比如點擊某個Button設置文本內容的更改)。
- LiveData並沒有提供這樣的功能,但是Architecture Component提供了MutableLiveData這樣一個類,可以通過setValue(T)和postValue(T)方法來修改存儲在LiveData中的數據。MutableLiveData是LiveData的一個子類,從名稱上也能看出這個類的作用。
- 調用setValue()方法就可以把LiveData中的值改為 "小楊真的是一個逗比么" 。同樣,通過這種方法修改LiveData中的值同樣會觸發所有對這個數據感興趣的類。那么setValue()和postValue()有什么不同呢?區別就是setValue()只能在主線程中調用,而postValue()可以在子線程中調用。
05.observe()和observerForever()
- 一般我們使用 LiveData 的 observe(),當數據更新后,LiveData 會通知它的所有活躍的觀察者。
- 與 RxJava 不同的,LiveData 只會通知活躍的觀察者,例如 Activity 位於 Destroyed 狀態時是不活躍的,因此不會收到通知。
- 當然我們也可以使用 LiveData 的 observerForever() 方法進行訂閱,區別是 observerForever() 不會受到 Activity 等組件的生命周期的影響,只要數據更新就會收到通知。
06.LiveData原理介紹
6.1 簡單的原理介紹
- LiveData可對數據進行觀測, 並具有生命周期感知能力, 這就意味着當liveData只會在生命周期處於活躍(inActive)的狀態下才會去執行觀測動作, 而他的能力賦予不能脫離LifeCycle的范圍。
- 需要注意的是,LiveData內維護的mVersion表示的是發送信息的版本,每次發送一次信息, 它都會+1, 而ObserverWrapper內維護的mLastVersion為訂閱觸發的版本號, 當訂閱動作生效的時候, 它的版本號會和發送信息的版本號同步.他們初始值都為-1。
6.2 然后思考一些問題
- a.liveData如何實現訂閱者模式,如何處理發送事件?
- b.如何做到感知生命周期的,怎么跟 LifecycleOwner 進行綁定的?
- c.LiveData 只在 LifecycleOwner active 狀態發送通知,是怎么處理的?
- d.LiveData 會自動在 DESTROY 的狀態下取消訂閱,是怎么處理的?
- e.生命周期變化后數據處理流程是怎么樣的?
- f.為什么觀察者只能與一個LifecycleOwner綁定,而不是多個?
07.observe訂閱源碼分析
7.1 首先看看observe方法源碼
- 直接查看源代碼,如下所示:
- 當前綁定的組件(activity或者fragment)狀態為DESTROYED的時候, 則會忽視當前的訂閱請求,也就是忽略owner的注冊;
- 如果需要與生命周期綁定, 則需要傳入LifecycleOwner對象, 將我們的LiveData數據觀測者(Observer)包裝注冊到生命周期的觀測者中, 就是源碼中創建wrapper對象過程;
- 需要注意的問題是,不能添加具有不同生命周期的相同觀察者,否則就會拋出IllegalArgumentException異常,但是owner可以add多個Observer;
- 最后添加一個LifecycleObserver,它將在LifecycleOwner更改狀態時得到通知,並做出及時的對應更新活動。
7.2 看看LifecycleBoundObserver源碼
- 然后看一下觀察者類LifecycleBoundObserver的源代碼
- LifecycleBoundObserver對象, 它繼承於ObserverWrapper, 並最終實現了GenericLifecycleObserver接口;
- 在發生狀態轉換事件時,會調用onStateChanged方法,在這個方法中,如果是DESTROYED狀態,則先要移除觀察者,然后在取到生命周期狀態變更事件
- 通過上面的代碼可以發現什么?
- GenericLifecycleObserver是一個接口,ObserverWrapper是一個抽象類,而LifecycleBoundObserver則是ObserverWrapper的子類,並且重寫了其中幾個方法;
- 在LifecycleBoundObserver的shouldBeActive()方法,在 owner 處於至少是 STARTED 的狀態下認為是 active 狀態;
- 而且它也實現了 GenericLifecycleObserver 接口,可以監聽 lifecycle 回調。在 onStateChanged() 方法里處理了生命周期改變的事件,在這個方法中,當接收到 DESTROYED 的事件會自動解除跟 owner 的綁定;
- 將下個流程交給了 activeStateChanged(),這里具體可以看抽象類ObserverWrapper中的activeStateChanged源碼;
- 看一下ObserverWrapper抽象類中activeStateChanged方法中,onActive和onInactive分別干什么呢?
- 對於onActive方法,當活動觀察者的數量從0變為1時調用;對於onInactive方法,當活動觀察者的數量從1變為0時調用
- 看一下ObserverWrapper抽象類中activeStateChanged方法中,dispatchingValue是干什么呢?
- 這個方法在分析下面setValue源碼時還會說到,具體看下面的介紹!
7.3 看看mObservers.putIfAbsent操作
- 關於observe源碼中這一行代碼ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper)作用是什么呢?
- mObservers.putIfAbsent(observer, wrapper)存入容器中,mObservers.putIfAbsent這個添加數據的方式比較少見。
- 看了下面源代碼可知,支持鍵值對存儲,用鏈表實現,不是線程安全的。既然這里有存數據,那肯定有地方會取數據用到,這個后面會說到……
7.4 注冊觀察者流程
- 那么注冊觀察者之后的觸發流程是怎樣的?
- 調用 observe() 注冊后,由於綁定了 owner,所以在 active 的情況下,使用LiveData中setValue發送數據,則 Observer 會立馬接受到該數據修改的通知。
- observe ——> onStateChanged ——> activeStateChanged ——> dispatchingValue ——> considerNotify ——> onChanged
- 至於最終走到了onChanged方法,這個方法則是交給外部開發者處理接收消息事件的邏輯
08.setValue發送源碼分析
8.1 setValue源碼分析
- LiveData 更新數據方式有兩個,一個是 setValue() 另一個是 postValue(),這兩個方法的區別是,postValue() 在內部會拋到主線程去執行更新數據,因此適合在子線程中使用;而 setValue() 則是直接更新數據。
- 跟進下 dispatchingValue() 方法,注意,這里需要重點看considerNotify代碼:
- 接下來看一下上面源碼中initiator對象為空判斷邏輯區別
- dispatchingValue 這里分兩種情況:ObserverWrapper不為null和ObserverWrapper為null
- ObserverWrapper不為null 的情況。LifecycleBoundObserver.onStateChanged 方法里調用了 activeStateChanged ,而該方法調用dispatchingValue(this);傳入了 this ,也就是 LifecycleBoundObserver ,這時候不為 null 。也就是說生命周期改變觸發的流程就是這種情況,這種情況下,只會通知跟該 Owner 綁定的 Observer。
- ObserverWrapper為null 的情況。經過分析發現在setValue方法中調用dispatchingValue(null)傳遞了空對象,這個時候的流程則會通知 active 的mObservers
8.2 看一下considerNotify()做什么
- 然后看一下considerNotify() 方法做了什么,代碼如下所示,這里有道詞典翻譯下注釋
- 如果ObserverWrapper的mLastVersion小於LiveData的mVersion,就會去回調mObserver的onChanged方法。
- 每個新的訂閱者,其version都是-1,LiveData一旦設置過其version是大於-1的(每次LiveData設置值都會使其version加1),這樣就會導致LiveDataBus每注冊一個新的訂閱者,這個訂閱者立刻會收到一個回調,即使這個設置的動作發生在訂閱之前。
- 思考一下dispatchingValue除了setValue會調用,其他還有地方調用么?
- dispatchingValue除了在我們主動更新數據的時候會觸發,
- 當LifeCircleOwner的狀態發生變化的時候,會調用LiveData.ObserverWrapper的activeStateChanged函數。
- 在我們的觀察者狀態變更(inactive->active)的時候, 也會通知到, 這就導致了LiveData必然支持粘性事件。
- 如果這個時候ObserverWrapper的狀態是active,就會調用LiveData的dispatchingValue。
- 它主要是處理分發通知邏輯,並且在分發通知前會判斷 owner 的狀態,再加上 LiveData 本身內部的版本管理,確保了只會發送最新的數據給 active 狀態下的 Observer。
- LiveData 對同時多次修改數據做了處理,如果同時多次修改,只會修改為最新的數據。
8.3 發送消息事件流程
- 那么發送消息事件之后的觸發流程是怎樣的?
- setValue ——> dispatchingValue(null) ——> considerNotify(注意,這里是個for迭代器循環,表示通知所有觀察者) ——> onChanged
09.observeForever源碼
- 這個方法是干什么用的呢?看一下源代碼
- 將給定的觀察者添加到觀察者列表中,意味着給定的觀察者將接收所有事件,並且永遠不會被自動刪除,不管在什么狀態下都能接收到數據的更改通知
10.LiveData源碼總結
- LiveData的觀察者可以聯動生命周期, 也可以不聯動。在聯動生命周期時,會自動在 DESTROYED 的狀態下移除 Observer ,取消訂閱,所以不用擔心內存泄露;
- LiveData的觀察者只能與一個LifecycleOwner綁定, 否則會拋出異常。而一個 owner 可以綁定多個 Observer 實例;
- LiveData 跟 LifecycleOwner 綁定,能感知生命周期變化,並且只會在 LifecycleOwner 處於 Active 狀態(STARTED/RESUMED)下通知數據改變;如果數據改變發生在非 active 狀態,數據會變化,但是不發送通知,等 owner 回到 active 的狀態下,再發送通知;
- 使用observeForever()方法,會注意AlwaysActiveObserver對象,意味着給定的觀察者將接收所有事件,並且永遠不會被自動刪除,不管在什么狀態下都能接收到數據的更改通知
- LiveData 利用版本管理、綁定 Lifecycle 確保了只會發送最新的數據給 active 狀態下的 Observer


參考博客
- https://developer.android.com/reference/android/arch/lifecycle/LiveData
- https://juejin.im/post/5dce5b16f265da0ba5279b11
- https://mp.weixin.qq.com/s/glbd3mzU_cUPGAlJMlQ5Hg
- https://github.com/googlesamples/android-architecture-components
- https://mp.weixin.qq.com/s/yzR2LAor7dUmZDctG2g7MQ


