LiveData
作為AAC架構的關鍵模塊之一秃臣,具有優(yōu)秀的生命周期感知特性。
本身采用觀察者模式诗轻,由于其生命周期感知特性雳窟,可以用來實現(xiàn)事件總線。
本文主要內容:
- 基本思路:基本的實現(xiàn)思路
- 粘性事件特性分析:
LiveData
觀察時推最新數據引發(fā)的問題 - 解決思路:解決思路和引入粘性事件
本文主要采用反射對Version進行管理魄梯,使用Class作為消息管理。
也可以使用其他實現(xiàn)方案,或在參考后自建方案:
Android消息總線的演進之路:用LiveDataBus替代RxBus淤击、EventBus
使用反射對Version進行管理
使用字符串的方式進行消息管理基于LiveData實現(xiàn)事件總線思路和方案
使用包裝類對Version進行管理
使用動態(tài)代理的方式進行信息管理
本文源碼直接拷貝即可使用。
也可以前往GitHub倉庫查看下載:LiveDataBus (采用反射+包裝類的形式)
基本思路:
-
observe()
:
即調用LiveData.observe()
故源,基于LiveData
的生命周期特性自動管理觀察者污抬。 -
observeForever()
:
即調用LiveData.observeForever()
,對無法提供LifecycleOwner
的觀察者進行支持绳军。 -
removeObserver()
:
即調用LiveData.removeObserver()
印机,移除對應觀察者。 -
postMessage()
:
發(fā)布任意類型的消息门驾,消息會通知所有關注此類型的觀察者射赛。
object LiveDataBus {
private val mBus: MutableMap<String, MutableLiveData<*>> = hashMapOf()
fun <T : Any> observe(channelClass: Class<T>, owner: LifecycleOwner, observer: Observer<T>) {
getChannel(channelClass).observe(owner, observer)
}
fun <T : Any> observeForever(channelClass: Class<T>, observer: Observer<T>) {
getChannel(channelClass).observeForever(observer)
}
fun <T : Any> removeObserver(channelClass: Class<T>, observer: Observer<T>) {
getChannel(channelClass).removeObserver(observer)
}
fun <T : Any> postMessage(message: T) {
getChannel(message::class.java as Class<T>).postValue(message)
}
private fun <T : Any> getChannel(channelClass: Class<T>): MutableLiveData<T> {
val channelName = channelClass.simpleName
if (!mBus.containsKey(channelName)) {
mBus[channelName] = MutableLiveData<T>()
}
return mBus[channelName] as MutableLiveData<T>
}
}
使用方式:
// 定義信息
class Message
// 訂閱信息
LiveDataBus.observe(Message::class.java, mAnyLifecycleOwner, Observer { })
LiveDataBus.observeForever(Message::class.java, Observer { })
// 發(fā)布信息
LiveDataBus.postMessage(Message())
粘性事件問題
網上很多LiveDataBus的實現(xiàn)都有對該問題進行分析,主要源自LiveData
的實時通知觀察者特性奶是,這個原來相當優(yōu)秀的機制楣责,在用來實現(xiàn)LiveDataBus的時候竣灌,反而會引發(fā)觀察時收到舊消息的問題。
解決方法并不復雜秆麸,通過自定義BusLiveData
繼承MutableLiveData
初嘹,并重寫observe()
和observeForever()
:
-
observe()
。
用于通過observe()
加入的observer
沮趣,通過反射屯烦,使ObserverWrapper
維護的數據版本等于當前LiveData
數據版本。
在觸發(fā)生命周期回調時房铭,由于數據版本相同漫贞,系統(tǒng)判斷為已通知,即不會觸發(fā)數據更新育叁。 -
observeForever()
:
使通過observeForever()
新加入的observer
迅脐,需要屏蔽所有通過observeForever()
發(fā)起的onChanged()
調用。
通過把傳入的observer
通過一個自定義的ObserverWrapper
裝修類豪嗽,在onChanged()
判斷當前調用棧是否有observeForever()
谴蔑,存在時則不觸發(fā)實際的observer.onChanged()
。
最終方案
最后修改后的LiveDataBus
:
/**
* LiveDataBus
* 基于LiveData實現(xiàn)的事件總線
*/
object LiveDataBus {
private val mBus by lazy { mutableMapOf<String, BusLiveData<*>>() }
fun <T : Any> observe(channel: Class<T>, owner: LifecycleOwner, observer: Observer<T>) {
getChannel(channel).observe(owner, observer)
}
fun <T : Any> observeSticky(channel: Class<T>, owner: LifecycleOwner, observer: Observer<T>) {
getChannel(channel).observeStick(owner, observer)
}
fun <T : Any> observeForever(channel: Class<T>, observer: Observer<T>) {
getChannel(channel).observeForever(observer)
}
fun <T : Any> observeStickyForever(channel: Class<T>, observer: Observer<T>) {
getChannel(channel).observeStickyForever(observer)
}
fun <T : Any> removeObserver(channelClass: Class<T>, observer: Observer<T>) {
getChannel(channelClass).removeObserver(observer)
}
fun <T : Any> postMessage(message: T) {
getChannel(message::class.java as Class<T>).postValue(message)
}
private fun <T : Any> getChannel(channelClass: Class<T>): BusLiveData<T> {
return mBus.getOrPut(channelClass.simpleName) {
BusLiveData<T>()
} as BusLiveData<T>
}
/**
* 自定義的LiveData
*
* 用于通過`observe()`加入的`observer`
* 通過反射龟梦,使`ObserverWrapper`維護的數據版本等于當前`LiveData`數據版本隐锭。
* 在觸發(fā)生命周期回調時,由于數據版本相同计贰,系統(tǒng)判斷為已通知钦睡,即不會觸發(fā)數據更新。
*
* 使通過`observeForever()`新加入的`observer`
* 需要屏蔽所有通過`observeForever()`發(fā)起的`onChanged()`調用躁倒。
* 通過把傳入的`observer`通過一個自定義的`ObserverWrapper`裝修類荞怒。
* 在`onChanged()`判斷當前調用棧是否有`observeForever()`,存在時則不觸發(fā)實際的`observer.onChanged()`秧秉。
*/
private class BusLiveData<T> : MutableLiveData<T>() {
// 反射緩存
private companion object {
private const val fieldObservers = "mObservers"
private const val methodGet = "get"
private const val fieldLastVersion = "mLastVersion"
private const val fieldVersion = "mVersion"
private val mCache = hashMapOf<String, Any>()
}
private val mRealMap = hashMapOf<Observer<*>, Observer<*>>()
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
setObserverVerToLiveDataVer(observer)
}
fun observeStick(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, observer)
}
override fun observeForever(observer: Observer<in T>) {
super.observeForever(mRealMap.getOrPut(observer) {
WrapperObserver(observer)
} as Observer<in T>)
}
fun observeStickyForever(observer: Observer<in T>) {
super.observeForever(observer)
}
override fun removeObserver(observer: Observer<in T>) {
if (mRealMap.containsKey(observer)) {
super.removeObserver(mRealMap.remove(observer) as Observer<T>)
} else {
super.removeObserver(observer)
}
}
private fun setObserverVerToLiveDataVer(observer: Observer<in T>) {
val liveDataClass = LiveData::class.java
try {
val mObserversField: Field = mCache.getOrPut(fieldObservers) {
val field = liveDataClass.getDeclaredField(fieldObservers)
field.isAccessible = true
field
} as Field
val mObservers = mObserversField[this]
val getMethod = mCache.getOrPut(methodGet) {
val method = mObservers.javaClass.getDeclaredMethod(methodGet, Any::class.java)
method.isAccessible = true
method
} as Method
val boundObserverEntry = getMethod.invoke(mObservers, observer)
var boundObserver: Any? = null
if (boundObserverEntry is Map.Entry<*, *>) {
boundObserver = boundObserverEntry.value
}
if (boundObserver == null) {
throw NullPointerException("LifecycleBoundObserver cant be null")
}
val mLastVersionField = mCache.getOrPut(fieldLastVersion) {
val wrapperClass: Class<in Any> = boundObserver.javaClass.superclass
?: throw NullPointerException("Cant access ObserverWrapper.class")
val field = wrapperClass.getDeclaredField(fieldLastVersion)
field.isAccessible = true
field
} as Field
val mVersionField = mCache.getOrPut(fieldVersion) {
val field = liveDataClass.getDeclaredField(fieldVersion)
field.isAccessible = true
field
} as Field
mLastVersionField.set(boundObserver, mVersionField[this])
} catch (e: Exception) {
}
}
}
/**
* Observer包裝類
*/
private class WrapperObserver<T>(
private val observer: Observer<T>
) : Observer<T> {
private companion object {
private const val clazz = "android.arch.lifecycle.LiveData"
private const val func = "observeForever"
}
override fun onChanged(t: T) {
if (!isCallOnObserve()) {
observer.onChanged(t)
}
}
private fun isCallOnObserve(): Boolean {
for (element in Thread.currentThread().stackTrace) {
if (clazz == element.className && func == element.methodName) {
return true
}
}
return false
}
}
}
使用方式:
// 定義信息
class Message
// 訂閱信息
LiveDataBus.observe(Message::class.java, this, Observer { })
LiveDataBus.observeForever(Message::class.java, Observer { })
// 訂閱粘性信息
LiveDataBus.observeSticky(Message::class.java, this, Observer { })
LiveDataBus.observeStickyForever(Message::class.java, Observer { })
// 發(fā)布信息
LiveDataBus.postMessage(Message())