背景
众所周知,LiveData 具有粘性特性,也即先 setValue/postValue 再 observe 也会收到 onChnaged 回调
一种解决思路
要解决粘性,不就是要判断是 setValue/postValue 和 observe 的先后关系吗?遂考虑用时间来进行判断,代码如下:
class NotStickyLiveData<T> : MutableLiveData<T> {
constructor(value: T) : super(value)
constructor() : super()
private var mNewValueTime = 0L
private val mObserverObserverMap = ConcurrentHashMap<Observer<in T>, Observer<T>>()
private val mOwnerObserversMap =
ConcurrentHashMap<LifecycleOwner, CopyOnWriteArrayList<Observer<in T>>>()
private val mObserverOwnerMap = ConcurrentHashMap<Observer<in T>, LifecycleOwner?>()
@MainThread
override fun setValue(value: T) {
mNewValueTime = System.currentTimeMillis()
super.setValue(value)
}
override fun postValue(value: T) {
mNewValueTime = System.currentTimeMillis()
super.postValue(value)
}
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
if (mObserverObserverMap.containsKey(observer)) {
if (mObserverOwnerMap[observer] == null) {
// 说明在 observeForever 中注册过
throw IllegalArgumentException("Cannot add the same observer with different lifecycles")
} else if (mObserverOwnerMap[observer] != owner) {
// 说明在 observe 中注册过但是 owner 不同
throw IllegalArgumentException("Cannot add the same observer with different lifecycles")
} else {
// 说明在 observe 中注册过,不再二次注册
return
}
}
val time = System.currentTimeMillis()
val newObserver = Observer<T> {
if (mNewValueTime > time) {
observer.onChanged(it)
}
}
mObserverObserverMap[observer] = newObserver
mObserverOwnerMap[observer] = owner
synchronized(this) {
if (mOwnerObserversMap[owner] == null) {
mOwnerObserversMap[owner] = CopyOnWriteArrayList()
}
}
mOwnerObserversMap[owner]!!.add(observer)
super.observe(owner, newObserver)
}
override fun observeForever(observer: Observer<in T>) {
if (mObserverObserverMap.containsKey(observer)) {
if (mObserverOwnerMap[observer] != null) {
// 说明在 observe 中注册过
throw IllegalArgumentException("Cannot add the same observer with different lifecycles")
} else {
// 说明在 observeForever 中注册过,不再二次注册
return
}
}
val time = System.currentTimeMillis()
val newObserver = Observer<T> {
if (mNewValueTime > time) {
observer.onChanged(it)
}
}
mObserverObserverMap[observer] = newObserver
mObserverOwnerMap[observer] = null
super.observeForever(newObserver)
}
override fun removeObserver(observer: Observer<in T>) {
mObserverObserverMap[observer]?.let {
mObserverObserverMap.remove(observer)
super.removeObserver(it)
}
mObserverObserverMap.remove(observer)
mObserverOwnerMap.remove(observer)
}
override fun removeObservers(owner: LifecycleOwner) {
mOwnerObserversMap[owner]?.let {
mOwnerObserversMap.remove(owner)
for (observer in it) {
removeObserver(observer)
}
}
}
}
思考
之所以提供这种思路,是因为有的开发者会把 LiveData 当成 EventBus 来使用,然而 Google 的初衷却只是用来更新 UI 的,当你 observe 时把最新的数据给你让你在 UI 上展示最新的状态也是合情合理的。
顺便提一下,多次 postValue 可能有些数据会“丢失”(当还没来得及把数据回调出去又被设置了更新的数据进来,就会直接用新数据覆盖老数据),其实这也是合理的,因为更新 UI 的状态可能赶不上你更新数据的频率,毕竟需要将最后的回调切换到 UI 线程上去执行。
其它
也许不是最好的方式,也许还存在问题,欢迎指正
网友评论