LiveDataBus大家都很熟悉了翎朱,網(wǎng)上也有很多通過反射實(shí)現(xiàn)的LiveDataBus。但是通過反射實(shí)現(xiàn)的代碼比較混亂尺铣,也比較難以理解拴曲。這里給出一版通過代碼實(shí)現(xiàn)的。更加的簡(jiǎn)潔優(yōu)雅~
首先來(lái)看一下LiveData原理
一般我們都是這樣使用的凛忿,創(chuàng)建一個(gè)LiveData去發(fā)送數(shù)據(jù)澈灼,在你想觀察的地方去注冊(cè)。這樣只要數(shù)據(jù)發(fā)射侄非,你就能拿到你想要的數(shù)據(jù)了蕉汪。
下面就是你再使用紅框語(yǔ)句時(shí)的調(diào)用流程
所以首先進(jìn)入 observe 方法看一看
這樣我們創(chuàng)建的LifecycleBoundObserver(observe方法中的new Observer
)
就和宿主(observe方法中傳入的this
) 建立了聯(lián)系。
所以宿主每次生命周期的變化都會(huì)調(diào)用到
LifecycleBoundObserver的onStateChanged
而從代碼中也可以看到逞怨,在宿主生命周期是DESTROYED時(shí)者疤,會(huì)主動(dòng)移除掉當(dāng)前mObserver,完成自動(dòng)反注冊(cè)叠赦,這里注意要把mObservers 和 mObserver分清楚
這里有幾點(diǎn)需要注意一下
1.LiveData中的mObservers是一個(gè)Map驹马,還有一個(gè)mVersion字段默認(rèn)等于 -1
2.LifecycleBoundObserver 繼承 ObserverWrapper
里面有mObserver,其實(shí)就是保存自己
還有一個(gè)mLastVersion字段除秀,默認(rèn)等于 -1
接下來(lái)繼續(xù)進(jìn)入activeStateChanged方法糯累,其他方法不多解釋。
這里直接進(jìn)入dispatchingValue
可以看到dispatchingValue不管走哪邊都會(huì)進(jìn)入considerNotify
接下來(lái)看considerNotify
看到這里我相信你已經(jīng)知道册踩,我們?yōu)樯赌茉賝nChanged拿到數(shù)據(jù)了
viewModel.liveDataObject.observe(this, new Observer<Bean>() {
@Override
public void onChanged(Bean data) {
接收數(shù)據(jù)
}
});
接下來(lái)看一下泳姐,postValue和setValue
可以看到setValue是有注解MainThread的,表示只能在主線程中使用
而postValue沒有暂吉,把某事件拋到主線程去了
再來(lái)來(lái)看一下胖秒,postValue在切換到主線程中都干了些啥,我們發(fā)現(xiàn)他的Runnable中的方法慕的,最終還是執(zhí)行了setValue阎肝。
所以這樣看
postValue只不過是可以在子線程執(zhí)行,但是消息發(fā)送最終還是要到主線程肮街,且執(zhí)行setValue
而setValue就只能在主線程執(zhí)行了
在執(zhí)行了setValue或者postValue后风题,mVersion+1,接著直接進(jìn)入到considerNotify
黏性事件怎么來(lái)的嫉父?
為了造成黏性事件沛硅,我再注冊(cè)觀察者之前就將數(shù)據(jù)發(fā)送出去,然后通過按鈕點(diǎn)擊再去注冊(cè)一個(gè)觀察者熔号,我們能發(fā)現(xiàn)稽鞭,即使是之前發(fā)送的數(shù)據(jù),仍然能夠接受得到引镊,這就是黏性事件朦蕴。
造成的原因就是mLastVersion 和 mVersion
實(shí)現(xiàn)自己的LiveDataBus
LiveData基本的都了解過了,接下來(lái)自己實(shí)現(xiàn)一個(gè)弟头,既可以接受黏性事件吩抓,又可以接受普通事件。
怎么控制黏性事件
其實(shí)原本的代碼就是可以發(fā)送事件的赴恨,只不過不能自由的控制黏性事件疹娶,
**如果我們能用一個(gè)變量去標(biāo)志就好了,比如這樣標(biāo)志一個(gè)receiveSticky變量**
為true就是接受黏性事件伦连,那么調(diào)用方法發(fā)送數(shù)據(jù)
為false的話就會(huì)雨饺,跳過此方法
if (observer.mLastVersion >= mVersion) {
return;
}
observer.mLastVersion = mVersion;
if(receiveSticky){
observer.mObserver.onChanged((T) mData);
} else {
// 處理普通事件
}
在假設(shè)我們能直接在源碼添加這個(gè)字段的話钳垮,那這個(gè)receiveSticky從哪里來(lái)呢?
1.發(fā)送者的角度:從 postValue 和 setValue 入手
比如改寫成 postValue(data,receiveSticky)
這樣有個(gè)弊端额港,這樣只能統(tǒng)一發(fā)送黏性或者非黏性饺窿,這樣如果多個(gè)宿主監(jiān)聽同一個(gè)消息,而有些需要黏性移斩,有些不需要肚医,這樣就很難控制
2.從接收者的角度:從observer入手
我們知道我們傳入的observer,在包裝成LifecycleBoundObserver后向瓷,才有mLastVersion肠套。那我們可以參考一下這種思路
比如:LifecycleBoundObserver包裝一下,有了mLastVersion
那么:我們將傳入的Observer也包裝一層猖任,在創(chuàng)建的時(shí)候傳入receiveSticky就好了
就像這樣:(當(dāng)然這不是完整版你稚,這只是記錄一下思路)
怎么保證接收的是同一個(gè)事件
liveData.postValue
viewModel.liveData.observer(this , Observer {
})
一般我們都是這樣發(fā)送接收的,這個(gè)LiveData都是同一個(gè)才能接收同一份數(shù)據(jù)朱躺。
所以我們也必須在LiveDataBus保證是同一個(gè)LiveData才行入宦。
還是同樣的思路,要區(qū)分LiveData室琢,就給LiveData加名字就行了唄
那我就再給LiveData包裝一層乾闰,讓調(diào)用者傳入名字去生成
生成完了就保存下來(lái),以后就用名字去找到對(duì)應(yīng)的LiveData
就好比:
那么他的用法就是這樣的:接收消息的有點(diǎn)過于復(fù)雜了盈滴。
既然observer是LiveData里面的方法涯肩,
而每次發(fā)送消息時(shí)間都是StickyObserver(sticky, Observer())
這樣我們就可以在我們的包裝類中去復(fù)寫一下observer,比如:
這樣發(fā)送接收數(shù)據(jù)就會(huì)變成巢钓,比之前稍微好一些
如何解決普通事件的接收
在上面我們其實(shí)沒對(duì)普通事件做處理
我們通過sticky能判斷接不接受黏性事件
但是我們不知道在我們注冊(cè)之前病苗,有沒有消息事件發(fā)送
override fun onChanged(t: T) {
if (sticky) {
observer.onChanged(t)
} else {
// 普通事件
}
}
回想一下,黏性事件是怎么產(chǎn)生的症汹?
簡(jiǎn)單的認(rèn)為硫朦,observer.mLastVersion(Observer的) < mVersion(LiveData的) 就會(huì)產(chǎn)生黏性事件
所以我們也可以模仿一下,弄兩個(gè)變量去判斷
在我們的LiveDate中
在我們的observe中會(huì)被改寫成這樣
所以顯然不能完全完全按照源碼照抄
那黏性事件之所以會(huì)被發(fā)送出去背镇,
就是在StickyObserver初始化時(shí)mLastVersion
和mLiveDataVersion
沒對(duì)齊咬展,
導(dǎo)致if (mLastVersion >= stickyLiveData.mLiveDataVersion) {}
沒進(jìn)入
所以進(jìn)入if條件就有黏性事件,所以我們要改成這樣
最后附上整個(gè)代碼瞒斩,直接復(fù)制就可以用
object LiveDataBus {
// LiveDataBus.with<String>("TestLiveDataBus").postStickyData("測(cè)試破婆!")
// LiveDataBus.with<String>("TestLiveDataBus") .observerSticky(this, false) {
//
// }
private val mStickyMap = ConcurrentHashMap<String, StickyLiveData<*>>()
fun <T> with(eventName: String): StickyLiveData<T> {
var stickyLiveData = mStickyMap[eventName]
if (stickyLiveData == null) {
stickyLiveData = StickyLiveData<T>(eventName)
mStickyMap[eventName] = stickyLiveData
}
return stickyLiveData as StickyLiveData<T>
}
/**
* 將發(fā)射出去的LiveData包裝一下,再做一些數(shù)據(jù)保存
*/
class StickyLiveData<T>(private var eventName: String) : LiveData<T>() {
var mLiveDataVersion = 0
var mStickyData: T? = null
fun setStickyData(stickyData: T) {
mStickyData = stickyData
setValue(stickyData)
}
fun postStickyData(stickyData: T) {
mStickyData = stickyData
postValue(stickyData)
}
override fun setValue(value: T) {
mLiveDataVersion++
super.setValue(value)
}
override fun postValue(value: T) {
super.postValue(value)
}
fun observerSticky(owner: LifecycleOwner, sticky: Boolean, observer: Observer<in T>) {
// 移除自己保存的StickyLiveData
owner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
mStickyMap.remove(eventName)
}
})
super.observe(owner, StickyObserver(this, sticky, observer))
}
/**
* 重寫LiveData的observer胸囱,把傳入的observer包裝一下
*/
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
observerSticky(owner,false, observer)
}
}
class StickyObserver<T>(
private val stickyLiveData: StickyLiveData<T>,
private val sticky: Boolean,
private val observer: Observer<in T>
) : Observer<T> {
/**
* 打個(gè)比方:
* 一條數(shù)據(jù)祷舀,名稱為TestName,
* 對(duì)應(yīng)一個(gè) StickyLiveData, 也就對(duì)應(yīng)一個(gè)version, 初始的值為0,且這個(gè)可以復(fù)用
* 且會(huì)創(chuàng)建StickyObserver裳扯,對(duì)應(yīng)一個(gè) mLastVersion, 初始的值為0
*
* 如果 StickyLiveData#version 和 StickyObserver#mLastVersion 沒有對(duì)齊
* LastVersion < version --> 直接發(fā)送數(shù)據(jù)抛丽,就會(huì)產(chǎn)生黏性事件
*
* 源碼就是這樣沒對(duì)齊,所以無(wú)法控制黏性事件
*
* 因?yàn)樵创a的流程
* 將傳入的observer包裝成LifecycleBoundObserver(繼承ObserverWrapper)會(huì)將傳入的observer做保存和保存在hashMap
* 最后在considerNotify遍歷hashMap,活躍的觀察者會(huì)調(diào)用observer.onChanged(t)去發(fā)送數(shù)據(jù)
*
* 所以這里把傳入的observer包裝成StickyObserver 進(jìn)入源碼后 --> 再變成LifecycleBoundObserver
* 所以最終發(fā)送數(shù)據(jù)會(huì)調(diào)用StickyObserver的onChanged 就可以做黏性事件的處理了
*
*/
private var mLastVersion = stickyLiveData.mLiveDataVersion
override fun onChanged(t: T) {
if (mLastVersion >= stickyLiveData.mLiveDataVersion) {
if (sticky && stickyLiveData.mStickyData != null) {
observer.onChanged(stickyLiveData.mStickyData)
}
return
}
observer.onChanged(t)
}
}
}