Jetpack之LiveData
1. 介紹
LiveData 具有生命周期感知能力,學(xué)習(xí)LiveData之前最好了解一下Lifecycle的知識(shí)廊散,以下是來自官網(wǎng)的介紹:
LiveData 是一種可觀察的數(shù)據(jù)存儲(chǔ)器類。與常規(guī)的可觀察類不同衔瓮,LiveData 具有生命周期感知能力见擦,意指它遵循其他應(yīng)用組件(如 Activity、Fragment 或 Service)的生命周期议蟆。這種感知能力可確保 LiveData 僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者。 如果觀察者(由 Observer 類表示)的生命周期處于 STARTED 或 RESUMED 狀態(tài)萎战,則 LiveData 會(huì)認(rèn)為該觀察者處于活躍狀態(tài)咐容。LiveData 只會(huì)將更新通知給活躍的觀察者。為觀察 LiveData 對(duì)象而注冊(cè)的非活躍觀察者不會(huì)收到更改通知蚂维。
使用 LiveData 具有以下優(yōu)勢(shì):
確保界面符合數(shù)據(jù)狀態(tài) LiveData 遵循觀察者模式戳粒。當(dāng)?shù)讓訑?shù)據(jù)發(fā)生變化時(shí),LiveData 會(huì)通知 Observer 對(duì)象虫啥。您可以整合代碼以在這些 Observer 對(duì)象中更新界面蔚约。這樣一來,您無需在每次應(yīng)用數(shù)據(jù)發(fā)生變化時(shí)更新界面涂籽,因?yàn)橛^察者會(huì)替您完成更新苹祟。
不會(huì)發(fā)生內(nèi)存泄漏 觀察者會(huì)綁定到 Lifecycle 對(duì)象,并在其關(guān)聯(lián)的生命周期遭到銷毀后進(jìn)行自我清理评雌。
不會(huì)因 Activity 停止而導(dǎo)致崩潰 如果觀察者的生命周期處于非活躍狀態(tài)(如返回棧中的 Activity)树枫,則它不會(huì)接收任何 LiveData 事件。
不再需要手動(dòng)處理生命周期 界面組件只是觀察相關(guān)數(shù)據(jù)景东,不會(huì)停止或恢復(fù)觀察砂轻。LiveData 將自動(dòng)管理所有這些操作,因?yàn)樗谟^察時(shí)可以感知相關(guān)的生命周期狀態(tài)變化斤吐。
數(shù)據(jù)始終保持最新狀態(tài) 如果生命周期變?yōu)榉腔钴S狀態(tài)搔涝,它會(huì)在再次變?yōu)榛钴S狀態(tài)時(shí)接收最新的數(shù)據(jù)厨喂。例如,曾經(jīng)在后臺(tái)的 Activity 會(huì)在返回前臺(tái)后立即接收最新的數(shù)據(jù)庄呈。
適當(dāng)?shù)呐渲酶? 如果由于配置更改(如設(shè)備旋轉(zhuǎn))而重新創(chuàng)建了 Activity 或 Fragment蜕煌,它會(huì)立即接收最新的可用數(shù)據(jù)。
共享資源 您可以使用單例模式擴(kuò)展 LiveData 對(duì)象以封裝系統(tǒng)服務(wù)诬留,以便在應(yīng)用中共享它們幌绍。LiveData 對(duì)象連接到系統(tǒng)服務(wù)一次,然后需要相應(yīng)資源的任何觀察者只需觀察 LiveData 對(duì)象故响。
2. 使用
使用LiveData分為創(chuàng)建傀广、監(jiān)聽(觀察)、通知(更新)三個(gè)步驟:
- 創(chuàng)建 LiveData 對(duì)象 LiveData 是一種可用于任何數(shù)據(jù)的封裝容器彩届,其中包括可實(shí)現(xiàn) Collections 的對(duì)象伪冰,如 List。LiveData 對(duì)象通常存儲(chǔ)在 ViewModel 對(duì)象中樟蠕,并可通過 getter 方法進(jìn)行訪問贮聂,如以下示例中所示:
class NameViewModel : ViewModel() {
// 創(chuàng)建一個(gè)String類型的LiveData
val currentName: MutableLiveData<String> by lazy {
MutableLiveData<String>()
}
}
最初,LiveData 對(duì)象中的數(shù)據(jù)并未經(jīng)過設(shè)置寨辩。
注意:請(qǐng)確保用于更新界面的 LiveData 對(duì)象存儲(chǔ)在 ViewModel 對(duì)象中吓懈,而不是將其存儲(chǔ)在 Activity 或 Fragment 中,原因如下:
- 避免 Activity 和 Fragment 過于龐大∶夷現(xiàn)在耻警,這些界面控制器負(fù)責(zé)顯示數(shù)據(jù),但不負(fù)責(zé)存儲(chǔ)數(shù)據(jù)狀態(tài)甸怕。
- 將 LiveData 實(shí)例與特定的 Activity 或 Fragment 實(shí)例分離開甘穿,并使 LiveData 對(duì)象在配置更改后繼續(xù)存在。
- 觀察 LiveData 對(duì)象 在大多數(shù)情況下梢杭,應(yīng)用組件的 onCreate() 方法是開始觀察 LiveData 對(duì)象的正確著手點(diǎn)温兼,原因如下:
- 確保系統(tǒng)不會(huì)從 Activity 或 Fragment 的 onResume() 方法進(jìn)行冗余調(diào)用。
- 確保 Activity 或 Fragment 變?yōu)榛钴S狀態(tài)后具有可以立即顯示的數(shù)據(jù)武契。一旦應(yīng)用組件處于 STARTED 狀態(tài)募判,就會(huì)從它正在觀察的 LiveData 對(duì)象接收最新值。只有在設(shè)置了要觀察的 LiveData 對(duì)象時(shí)咒唆,才會(huì)發(fā)生這種情況届垫。
通常,LiveData 僅在數(shù)據(jù)發(fā)生更改時(shí)才發(fā)送更新钧排,并且僅發(fā)送給活躍觀察者敦腔。此行為的一種例外情況是均澳,觀察者從非活躍狀態(tài)更改為活躍狀態(tài)時(shí)也會(huì)收到更新恨溜。此外符衔,如果觀察者第二次從非活躍狀態(tài)更改為活躍狀態(tài),則只有在自上次變?yōu)榛钴S狀態(tài)以來值發(fā)生了更改時(shí)糟袁,它才會(huì)收到更新判族。 以下示例代碼說明了如何開始觀察 LiveData 對(duì)象:
class NameActivity : AppCompatActivity() {
// 'by viewModels()'是 activity-ktx 組件,使用 ViewModelProvider 初始化NameViewModel也可以
private val model: NameViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 省略其他代碼...
// 創(chuàng)建更新UI的觀察者
val nameObserver = Observer<String> { newName ->
// 更新UI项戴,這里是TextView的文本內(nèi)容
nameTextView.text = newName
}
// 觀察LiveData形帮,將this作為LifecycleOwner和觀察者傳入。
model.currentName.observe(this, nameObserver)
}
}
在傳遞 nameObserver
參數(shù)的情況下調(diào)用 observe()
后周叮,系統(tǒng)會(huì)立即調(diào)用onChanged()
辩撑,從而提供 mCurrentName
中存儲(chǔ)的最新值。如果 LiveData
對(duì)象尚未在 mCurrentName
中設(shè)置值仿耽,則不會(huì)調(diào)用 onChanged()
合冀。
這句話的意思是, nameObserver
先改變?cè)俦O(jiān)聽(觀察)项贺,依舊可以觀察到改變后的數(shù)據(jù)君躺,即LiveData是有粘性的。
- 更新 LiveData 對(duì)象 LiveData 沒有公開可用的方法來更新存儲(chǔ)的數(shù)據(jù)开缎。
MutableLiveData
類將公開setValue(T)
和postValue(T)
方法棕叫,如果您需要修改存儲(chǔ)在LiveData
對(duì)象中的值,則必須使用這些方法奕删。通常情況下會(huì)在ViewModel
中使用MutableLiveData
俺泣,然后ViewModel
只會(huì)向觀察者公開不可變的 LiveData 對(duì)象。
設(shè)置觀察者關(guān)系后完残,您可以更新LiveData
對(duì)象的值(如以下示例中所示)砌滞,這樣當(dāng)用戶點(diǎn)按某個(gè)按鈕時(shí)會(huì)觸發(fā)所有觀察者:
button.setOnClickListener {
val anotherName = "John Doe"
model.currentName.setValue(anotherName)
}
在本示例中調(diào)用 setValue(T)
導(dǎo)致觀察者使用值John Doe
調(diào)用其 onChanged()
方法。本示例中演示的是按下按鈕的方法坏怪,但也可以出于各種各樣的原因調(diào)用 setValue()
或 postValue()
來更新 mName
贝润,這些原因包括響應(yīng)網(wǎng)絡(luò)請(qǐng)求或數(shù)據(jù)庫加載完成。在所有情況下铝宵,調(diào)用 setValue()
或 postValue()
都會(huì)觸發(fā)觀察者并更新界面打掘。
注意:您必須調(diào)用 setValue(T) 方法以從主線程更新 LiveData 對(duì)象。如果在工作器線程中執(zhí)行代碼鹏秋,您可以改用 postValue(T) 方法來更新 LiveData 對(duì)象尊蚁。
3. 分析
基于androidx.lifecycle:lifecycle-livedata-core:2.3.1
根據(jù)前面的介紹,思考幾個(gè)問題:
LiveData如何做到僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者侣夷?
LiveData粘性效果是怎么實(shí)現(xiàn)的横朋?能否去掉?如何去掉粘性效果百拓?
LiveData中的setValue(T)和postValue(T)有什么區(qū)別琴锭?內(nèi)部分別怎么實(shí)現(xiàn)的晰甚?
3.1 LiveData的相關(guān)類和結(jié)構(gòu)
首先看一下源碼包,基于androidx.lifecycle:lifecycle-livedata-core:2.3.1
:
可以看到源碼包中的類出奇的少决帖,但是其內(nèi)部用到了Lifecycle的相關(guān)類厕九,看一下類圖:
LiveData本身是一個(gè)很簡單的觀察者模式,通過observe(LifecycleOwner owner, @Observer<? super T> observer)
方法向其成員變量SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers
添加觀察者地回,在數(shù)據(jù)發(fā)生改變時(shí)調(diào)用setValut(T)
或postValue(T)
來通知觀察者發(fā)生數(shù)據(jù)改變扁远。
那么LiveData如何做到僅更新處于活躍生命周期狀態(tài)的應(yīng)用組件觀察者,原理也比較簡單刻像,維護(hù)一個(gè)成員變量boolean mActive
畅买,在通知觀察者之前判斷該變量為true
時(shí)則通知,否則不通知细睡。而boolean mActive
表示了觀察者當(dāng)前是否為活躍狀態(tài)皮获,這個(gè)狀態(tài)的改變則依賴于Lifecycle
生命周期組件。
- Observer
Observer
只有一個(gè)方法的觀察者纹冤,LiveData發(fā)生變化時(shí)通知的就是它洒宝。
- LiveData
關(guān)鍵類,所有關(guān)鍵源碼也基本上在這個(gè)類里萌京,后面分析源碼時(shí)詳細(xì)講解:
內(nèi)部維護(hù)了觀察者列表雁歌、提供了添加觀察者的方法、數(shù)據(jù)更新方法(通知觀察者)知残;
一個(gè)內(nèi)部抽象類
ObserverWrapper
靠瞎,關(guān)鍵變量boolean mActive
由它維護(hù);兩個(gè)內(nèi)部類
LifecycleBoundObserver
和AlwaysActiveObserver
求妹,類圖中有說明區(qū)別乏盐;
- MutableLiveData
由于LiveData
中的 setValue(T)
和postValue(T)
是protected
,外部無法訪問制恍,那么該怎么更新內(nèi)容呢父能?Android提供了MutableLiveData
,該類目前也只有一個(gè)作用净神,即將 setValue(T)
和postValue(T)
方法公開public
何吝。
LifecycleObserver
和LifecycleEventObserver
是Lifecycle
的知識(shí),這里不想詳細(xì)講解鹃唯,可以查看Jetpack之Lifecycle
3.2 源碼分析
了解了這幾個(gè)類的基本關(guān)系爱榕,接下來重點(diǎn)分析一下LiveData
,根據(jù)使用的三步來分析第一步:創(chuàng)建LiveData
3.2.1 創(chuàng)建過程分析
public abstract class LiveData<T> {
// liveData持有的數(shù)據(jù)
private volatile Object mData;
// mVersion可以理解為mData的版本坡慌,即更新次數(shù)黔酥,會(huì)作為是否通知觀察者的判斷依據(jù);只增不減
private int mVersion;
// 初始默認(rèn)版本
static final int START_VERSION = -1;
// 空對(duì)象
static final Object NOT_SET = new Object();
// 帶參構(gòu)造函數(shù),同時(shí)mVersion版本 +1
public LiveData(T value) {
mData = value;
mVersion = START_VERSION + 1;
}
// 無參構(gòu)造函數(shù)跪者,mData賦值默認(rèn)數(shù)據(jù)棵帽,mVersion為初始版本
public LiveData() {
mData = NOT_SET;
mVersion = START_VERSION;
}
}
3.2.2 監(jiān)聽(觀察)過程分析
(1)注冊(cè)觀察者
LiveData
提供了兩個(gè)觀察方法observe(...)
和observeForever(...)
,其中observeForever(...)
與生命周期無關(guān)也比較簡單坑夯,看一下LiveData
關(guān)于該方法的源碼:
public abstract class LiveData<T> {
// 觀察者集合
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
// 該方法必須在主線程調(diào)用
@MainThread
public void observeForever(@NonNull Observer<? super T> observer) {
// 判斷是否在主線程,若不在則拋異常
assertMainThread("observeForever");
// 將觀察者包裝到AlwaysActiveObserver
AlwaysActiveObserver wrapper = new AlwaysActiveObserver(observer);
// 將包裝后的觀察者添加到觀察者列表中抡四;若已添加則返回該對(duì)象柜蜈,若未添加在則添加并返回為空
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// 如果觀察者為LifecycleBoundObserver則拋異常,同一個(gè)觀察者observer不能被包裝2次指巡,
if (existing instanceof LiveData.LifecycleBoundObserver) {
// 翻譯一下:不能添加具有不同生命周期的同一個(gè)觀察者
throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
}
// 如果不為空則表示添加過(mObservers內(nèi)已存在)淑履,直接返回;為空則表示第一次添加藻雪,需要執(zhí)行后面的邏輯
if (existing != null) {
return;
}
// 此處為第1中情況調(diào)用activeStateChanged()方法
// * 狀態(tài)改變秘噪,正是由于這句代碼帶來了粘性效果;由于該類沒有關(guān)聯(lián)生命周期所以默認(rèn)觀察者始終處于活躍狀態(tài)勉耀,故直接調(diào)用并傳遞 true
wrapper.activeStateChanged(true);
}
private abstract class ObserverWrapper {
// 被包裝的觀察者
final Observer<? super T> mObserver;
// 觀察者是否處于或者狀態(tài)的標(biāo)記變量
boolean mActive;
// 觀察者觀察到的數(shù)據(jù)版本
int mLastVersion = START_VERSION;
// other code ...
// 該方法作用類似于mActive指煎,但比mActive更精確;由子類實(shí)現(xiàn)
abstract boolean shouldBeActive();
// 是否關(guān)聯(lián)到入?yún)⒌纳芷诒愠猓荒J(rèn)為false
boolean isAttachedTo(LifecycleOwner owner) {
return false;
}
// 解除觀察者
void detachObserver() {
}
// 有4種情況會(huì)調(diào)用該方法:1.observeForever初次添加觀察者時(shí)至壤;2.數(shù)據(jù)變更時(shí);3.移除觀察者時(shí)枢纠;4.生命周期改變時(shí)像街;
void activeStateChanged(boolean newActive) {
// 新狀態(tài)和當(dāng)前狀態(tài)一致則不處理
if (newActive == mActive) {
return;
}
// immediately set active state, so we'd never dispatch anything to inactive owner
// 翻譯一下:立即設(shè)置活動(dòng)狀態(tài),這樣我們就不會(huì)將任何東西分派給不活動(dòng)的所有者
// 意思是:先改狀態(tài)后分發(fā)晋渺,為什么不是先分發(fā)再改狀態(tài)呢镰绎?
// 舉例舊狀態(tài)為true新狀態(tài)為false,先分發(fā)的情況下木西,mActive還未被賦予新狀態(tài)畴栖,此時(shí)仍是ture,則同樣會(huì)執(zhí)行dispatchingValue()方法八千,若先賦值則不存在該情況
mActive = newActive;
// 調(diào)用外部類的方法驶臊,內(nèi)部會(huì)經(jīng)過判斷調(diào)用liveData 的 onActive()或onInactive()方法,表示當(dāng)前觀察者是否處于活躍狀態(tài)
changeActiveCounter(mActive ? 1 : -1);
// 若狀態(tài)未活躍叼丑,則分發(fā)數(shù)據(jù)
if (mActive) {
// * 分發(fā)數(shù)據(jù)
dispatchingValue(this);
}
}
}
// 該類未覆蓋父類的 detachObserver() 方法
private class AlwaysActiveObserver extends ObserverWrapper {
AlwaysActiveObserver(Observer<? super T> observer) {
super(observer);
}
// 這里固定返回為ture关翎,即表示觀察者一直為活躍狀態(tài)
@Override
boolean shouldBeActive() {
return true;
}
}
}
上面分析了observeForever(...)
方法,注意activeStateChanged(boolean newActive)
有4種情況會(huì)調(diào)用:
observeForever初次添加觀察者時(shí)(上已經(jīng)介紹鸠信,粘性效果的關(guān)鍵)
數(shù)據(jù)變更時(shí)纵寝,根據(jù)實(shí)時(shí)狀態(tài)判斷調(diào)用
移除觀察者時(shí)
觀察者生命周期改變時(shí)
這里記住在無關(guān)聯(lián)生命周期的方法observeForever(...)
的內(nèi)部會(huì)調(diào)用到dispatchingValue(this)
方法;
接下來看一下看一下LiveData
關(guān)于observe()
方法的源碼:
public abstract class LiveData<T> {
// 觀察者集合
private SafeIterableMap<Observer<? super T>, ObserverWrapper> mObservers = new SafeIterableMap<>();
// 該方法必須在主線程調(diào)用;接收生命周期持有者和觀察者2個(gè)參數(shù)
@MainThread
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
// 判斷是否在主線程爽茴,若不在則拋異常
assertMainThread("observe");
// 判斷需要關(guān)聯(lián)的生命周期持有的狀態(tài)葬凳,如果為DESTROYED狀態(tài)則不處理;即已經(jīng)銷毀的觀察者沒有必要再觀察數(shù)據(jù)
if (owner.getLifecycle().getCurrentState() == DESTROYED) {
// ignore
return;
}
// 將觀察者包裝到 LifecycleBoundObserver
LifecycleBoundObserver wrapper = new LifecycleBoundObserver(owner, observer);
// 將包裝后的觀察者添加到觀察者列表中室奏;若已添加則返回該對(duì)象火焰,若未添加在則添加并返回為空
ObserverWrapper existing = mObservers.putIfAbsent(observer, wrapper);
// mObservers內(nèi)已存在并且不是同一生命周期持有者則拋異常;即同一觀察者不能關(guān)聯(lián)不同的生命周期持有者
if (existing != null && !existing.isAttachedTo(owner)) {
throw new IllegalArgumentException("Cannot add the same observer with different lifecycles");
}
// 如果不為空則表示添加過(mObservers內(nèi)已存在)胧沫,直接返回昌简;為空則表示第1次添加,需要執(zhí)行后面的邏輯
if (existing != null) {
return;
}
// 第1次添加該觀察者绒怨,則將其與生命周期關(guān)聯(lián)
owner.getLifecycle().addObserver(wrapper);
}
class LifecycleBoundObserver extends ObserverWrapper implements LifecycleEventObserver {
@NonNull
final LifecycleOwner mOwner;
// 省略其他代碼
// 判斷觀察者狀態(tài)是否為活躍狀態(tài)纯赎;LiveData 感知生命周期的關(guān)鍵也是這里
@Override
boolean shouldBeActive() {
return mOwner.getLifecycle().getCurrentState().isAtLeast(STARTED);
}
// 當(dāng)生命周期組件(Activity、Fragment等)狀態(tài)發(fā)生改變時(shí)(create南蹂、resume等)會(huì)觸發(fā)該方法犬金;更多內(nèi)容需了解Lifycycle知識(shí)
// observe()是在onCreate時(shí)調(diào)用,而observe()內(nèi)部添加了生命周期變化的感知能力六剥。那么在Lifecycle.Event為onCrate時(shí)晚顷,這里是否能接收到回調(diào)呢?答案是可的疗疟,因?yàn)閛nCrate事件是在Activity等執(zhí)行完之后音同,才會(huì)通知觀察者
@Override
public void onStateChanged(@NonNull LifecycleOwner source,
@NonNull Lifecycle.Event event) {
Lifecycle.State currentState = mOwner.getLifecycle().getCurrentState();
// 生命周期處于DESTROYED時(shí),移除觀察者并返回秃嗜;而其他狀態(tài)則會(huì)繼續(xù)執(zhí)行
if (currentState == DESTROYED) {
removeObserver(mObserver);
return;
}
// 這里的 currentState 和 prevState 都為局部變量权均;為什么要?jiǎng)?chuàng)建prevState并賦值呢?了解的小伙伴指導(dǎo)一下...
Lifecycle.State prevState = null;
while (prevState != currentState) {
prevState = currentState;
// * 這里是第4種情況下調(diào)用activeStateChanged()方法锅锨,若數(shù)據(jù)已經(jīng)發(fā)生變化叽赊,即使剛剛添加的觀察者也可以收到新數(shù)據(jù)(LiveData的粘性效果)
activeStateChanged(shouldBeActive());
currentState = mOwner.getLifecycle().getCurrentState();
}
}
@Override
boolean isAttachedTo(LifecycleOwner owner) {
return mOwner == owner;
}
// 解除觀察者
@Override
void detachObserver() {
// 從生命周期中移除觀察者
mOwner.getLifecycle().removeObserver(this);
}
}
}
LiveData感知生命周期的能力關(guān)鍵在于owner.getLifecycle().addObserver(wrapper);
,上面分析了觀察者生命周期改變時(shí)會(huì)調(diào)用activeStateChanged()
方法必搞,且在Activity的onCreate中添加觀察者依舊可以接收到改變后的數(shù)據(jù)(粘性效果)必指。
總結(jié)一下注冊(cè)觀察者:在注冊(cè)觀察者時(shí)會(huì)根據(jù)調(diào)用不同的方法將觀察者包裝到不同的wapper中,添加到觀察者集合里恕洲,并調(diào)用分發(fā)數(shù)據(jù)方法通知觀察者最新數(shù)據(jù)(若有)塔橡,達(dá)到粘性效果。
(2)dispatchingValue(...)分析
上面分析了2種調(diào)用activeStateChanged(boolean newActive)
的情況:
- observeForever初次添加觀察者時(shí)
- 觀察者生命周期改變時(shí)
接下來分析一下該方法內(nèi)部的關(guān)鍵方法dispatchingValue()
霜第,該方法在setValue()方法內(nèi)也會(huì)調(diào)用葛家。
public abstract class LiveData<T> {
@SuppressWarnings("WeakerAccess") /* synthetic access */
/*
* 分發(fā)數(shù)據(jù),在數(shù)據(jù)發(fā)生改變或生命周期發(fā)生改變等情況下會(huì)調(diào)用該方法
* 接收一個(gè)觀察者參數(shù)
*/
void dispatchingValue(@Nullable ObserverWrapper initiator) {
if (mDispatchingValue) {
mDispatchInvalidated = true;
return;
}
mDispatchingValue = true;
do {
mDispatchInvalidated = false;
// 若傳入的指定觀察者不為空則通知指定觀察者
if (initiator != null) {
// 通知觀察者
considerNotify(initiator);
initiator = null;
} else {
// 若傳入的指定觀察者為空泌类,則通知觀察者集合(mObservers)里面的所有觀察者
for (Iterator<Map.Entry<Observer<? super T>, ObserverWrapper>> iterator =
mObservers.iteratorWithAdditions(); iterator.hasNext(); ) {
// 通知觀察者
considerNotify(iterator.next().getValue());
if (mDispatchInvalidated) {
break;
}
}
}
} while (mDispatchInvalidated);
mDispatchingValue = false;
}
// 通知觀察者
private void considerNotify(ObserverWrapper observer) {
// 如果觀察者不活躍則直接返回
if (!observer.mActive) {
return;
}
// Check latest state b4 dispatch. Maybe it changed state but we didn't get the event yet.
//
// we still first check observer.active to keep it as the entrance for events. So even if
// the observer moved to an active state, if we've not received that event, we better not
// notify for a more predictable notification order.
// 直譯:也許它改變了狀態(tài)癞谒,但我們還沒有得到事件。 我們?nèi)匀皇紫葯z查[observer.active]以保持它作為事件的入口。 因此弹砚,即使觀察者移動(dòng)到活動(dòng)狀態(tài)双仍,如果我們沒有收到該事件,我們最好不要通知桌吃。
// 也就是說:觀察者內(nèi)部的成員變量 mActive 可能已經(jīng)改變?yōu)榛钴S狀態(tài)朱沃,但是還沒有收到生命周期組件的事件通知;即加此判斷可以保證更加準(zhǔn)確的獲取觀察者的實(shí)時(shí)狀態(tài)茅诱。
if (!observer.shouldBeActive()) {
// 糾正觀察者的正確狀態(tài)逗物;第2種情況調(diào)用activeStateChanged()方法
observer.activeStateChanged(false);
return;
}
// 若之前的版本號(hào)高于或等于當(dāng)前版本號(hào)則直接返回;只有當(dāng)前版本大于舊版本時(shí)才繼續(xù)執(zhí)行让簿;mVersion 該變量會(huì)在每次 setValue 時(shí) +1
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
// 通知觀察者數(shù)據(jù)已更新
observer.mObserver.onChanged((T) mData);
}
}
(3)注銷觀察者
注銷觀察者也有2個(gè)方法:
public abstract class LiveData<T> {
// 移除指定觀察者
@MainThread
public void removeObserver(@NonNull final Observer<? super T> observer) {
// 判斷是否在主線程敬察,不在則拋異常
assertMainThread("removeObserver");
// 從觀察者列表中移除
ObserverWrapper removed = mObservers.remove(observer);
if (removed == null) {
return;
}
// 已移除的觀察者解除對(duì)生命周期組件的關(guān)聯(lián)
removed.detachObserver();
// 移除的觀察者置為非活躍狀態(tài)秀睛;第3種情況調(diào)用activeStateChanged()方法
removed.activeStateChanged(false);
}
/**
* 移除給定生命周期組件所關(guān)聯(lián)的所有觀察者
*/
@SuppressWarnings("WeakerAccess")
@MainThread
public void removeObservers(@NonNull final LifecycleOwner owner) {
// 判斷是否在主線程尔当,不在則拋異常
assertMainThread("removeObservers");
// 遍歷觀察者列表
for (Map.Entry<Observer<? super T>, ObserverWrapper> entry : mObservers) {
// 如果是與給定的觀察者一致,則調(diào)用 removeObserver(...)方法
if (entry.getValue().isAttachedTo(owner)) {
removeObserver(entry.getKey());
}
}
}
}
注冊(cè)蹂安、注銷觀察者的流程就分析完了椭迎,關(guān)于前面問題提到的粘性效果在分析過程中也提到了,即在注冊(cè)觀察者時(shí)調(diào)用了通知觀察者數(shù)據(jù)改變的方法田盈。那么能否去掉粘性效果呢畜号?如何去掉?
首先通過上面的分析可以知道允瞧,在真正調(diào)用觀察者的onChange(T)
之前會(huì)有3次判斷简软,可以通過改變其中1個(gè)的判斷條件即可:
// 通知觀察者
private void considerNotify(ObserverWrapper observer) {
// 第1次判斷
if (!observer.mActive) {
return;
}
// 第2次判斷
if (!observer.shouldBeActive()) {
observer.activeStateChanged(false);
return;
}
// 第3次判斷
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
observer.mObserver.onChanged((T) mData);
}
前2次判斷都是和觀察者的活躍狀態(tài)有關(guān),而這個(gè)活躍狀態(tài)和生命周期相關(guān)述暂,不能輕易修改痹升。第3次判斷數(shù)據(jù)版本看起來可行,它本身就是標(biāo)記數(shù)據(jù)版本的畦韭,那么久從它下手疼蛾。
粘性效果是指:數(shù)據(jù)先發(fā)生改變,后注冊(cè)觀察者也可以收到數(shù)據(jù)改變艺配。數(shù)據(jù)發(fā)生了改變察郁,其持有的成員變量private int mVersion
就大于0;而后注冊(cè)觀察者转唉,在觀察者包裝類中的成員變量被賦值為int mLastVersion = START_VERSION(-1)
皮钠,observer.mLastVersion >= mVersion
條件不成立,故會(huì)通知觀察者赠法。去掉粘性效果:在注冊(cè)時(shí)將mVersion
的值賦值給mLastVersion
即可使該條件成立鳞芙,不再通知觀察者。附上一段大神的實(shí)現(xiàn):
public class UnPeekLiveData<T> extends MutableLiveData<T> {
@Override
public void observe(@NonNull LifecycleOwner owner, @NonNull Observer<? super T> observer) {
super.observe(owner, observer);
hook(observer);
}
private void hook(Observer<? super T> observer) {
Class<LiveData> liveDataClass = LiveData.class;
try {
//獲取field private SafeIterableMap<Observer<T>, ObserverWrapper> mObservers
Field mObservers = liveDataClass.getDeclaredField("mObservers");
mObservers.setAccessible(true);
//獲取SafeIterableMap集合mObservers
Object observers = mObservers.get(this);
Class<?> observersClass = observers.getClass();
//獲取SafeIterableMap的get(Object obj)方法
Method methodGet = observersClass.getDeclaredMethod("get", Object.class);
methodGet.setAccessible(true);
//獲取到observer在集合中對(duì)應(yīng)的ObserverWrapper對(duì)象
Object objectWrapperEntry = methodGet.invoke(observers, observer);
Object objectWrapper = null;
if (objectWrapperEntry instanceof Map.Entry) {
objectWrapper = ((Map.Entry) objectWrapperEntry).getValue();
}
if (objectWrapper == null) {
throw new NullPointerException("ObserverWrapper can not be null");
}
//獲取ObserverWrapper的Class對(duì)象 LifecycleBoundObserver extends ObserverWrapper
Class<?> wrapperClass = objectWrapper.getClass().getSuperclass();
//獲取ObserverWrapper的field mLastVersion
Field mLastVersion = wrapperClass.getDeclaredField("mLastVersion");
mLastVersion.setAccessible(true);
//獲取liveData的field mVersion
Field mVersion = liveDataClass.getDeclaredField("mVersion");
mVersion.setAccessible(true);
Object mV = mVersion.get(this);
//把當(dāng)前ListData的mVersion賦值給 ObserverWrapper的field mLastVersion
mLastVersion.set(objectWrapper, mV);
mObservers.setAccessible(false);
methodGet.setAccessible(false);
mLastVersion.setAccessible(false);
mVersion.setAccessible(false);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2.3 更新 LiveData 對(duì)象分析
分析一下更新LiveData持有的數(shù)據(jù)源碼:
public abstract class LiveData<T> {
// 延遲的數(shù)據(jù)
volatile Object mPendingData = NOT_SET;
private final Runnable mPostValueRunnable = new Runnable() {
@SuppressWarnings("unchecked")
@Override
public void run() {
Object newValue;
synchronized (mDataLock) {
// 將延遲數(shù)據(jù)賦值給局部變量newValue
newValue = mPendingData;
mPendingData = NOT_SET;
}
// 將newValue作為入?yún)⒄{(diào)用setValue方法
setValue((T) newValue);
}
};
// 可以在子線程調(diào)用
protected void postValue(T value) {
boolean postTask;
synchronized (mDataLock) {
postTask = mPendingData == NOT_SET;
// 將數(shù)據(jù)賦值給延遲數(shù)據(jù)mPendingData
mPendingData = value;
}
if (!postTask) {
return;
}
// 內(nèi)部會(huì)追溯到 DefaultTaskExecutor ,是通過 Handler 實(shí)現(xiàn)的調(diào)度
ArchTaskExecutor.getInstance().postToMainThread(mPostValueRunnable);
}
// 必須在主線程調(diào)用
@MainThread
protected void setValue(T value) {
// 判斷是否在主線程原朝,否則拋異常
assertMainThread("setValue");
// 數(shù)據(jù)版本 +1
mVersion++;
// 給數(shù)據(jù)賦值
mData = value;
// 分發(fā)數(shù)據(jù)驯嘱;內(nèi)部分析查看 [dispatchingValue(...)分析]
dispatchingValue(null);
}
}
問題:
分析如下代碼,分析觀察者收到的數(shù)據(jù)( ):
// 在主線程按如下順序調(diào)用 liveData.postValue("a"); liveData.setValue("b");
A. a
B. b
C. a b
D. b a解析:更新了2次數(shù)據(jù)且調(diào)用的是不同方法喳坠,所以首先排除 A B 鞠评;接著分析順序,由于
setValue(T)
是直接通知更新壕鹉,所以觀察者會(huì)首先收到 ‘b’ 剃幌;postValue(T)
是將新數(shù)據(jù)賦值給mPendingData
,等到Handler調(diào)度執(zhí)行時(shí)才會(huì)調(diào)用setValue(T)
將mPendingData
的數(shù)據(jù)通知給觀察者晾浴,故'a'后收到负乡。答案:D.
源碼注釋中還有:如果在主線程執(zhí)行提交的任務(wù)之前多次調(diào)用此方法,則只會(huì)分派最后一個(gè)值脊凰。也比較容易理解抖棘,"主線程執(zhí)行提交的任務(wù)之前多次調(diào)用此方法"mPendingData
會(huì)一直被賦值為新值,在執(zhí)行調(diào)度時(shí)也只有最后一個(gè)值會(huì)被分派狸涌。