open class NoStickLiveData<T : Any> : SafeLiveData<T> {
private var mVersion:Int
//反射拿到父类的field mObservers。
private var mObservers:(java.lang.Iterable<java.util.Map.Entry<*, *>>)? = null
private fun requireMObservers() : java.lang.Iterable<java.util.Map.Entry<*, *>> {
val mOb = mObservers
if (mOb == null) {
var superClass: Class<*>? = javaClass.superclass
while (superClass != null && superClass != Any::class.java) {
if (superClass == LiveData::class.java) {
val field = superClass.getDeclaredField("mObservers")
field.isAccessible = true
val o = field.get(this)
mObservers = o as java.lang.Iterable<java.util.Map.Entry<*, *>>
break
}
superClass = superClass.superclass
}
return mObservers!!
}
return mOb
}
constructor() {
mVersion = -1
}
constructor(data:T?) : super(data) {
mVersion = 0
}
override fun setValue(value: T?) {
mVersion++
super.setValue(value)
}
override fun removeObserver(observer: Observer<in T>) {
super.removeObserver(observer)
removeObserverUnStick(observer)
}
/**
* 追加不处理粘性的方式
*/
fun observeUnStick(owner: LifecycleOwner, observer: Observer<in T>) {
super.observe(owner, NoStickWrapObserver(this, observer = observer))
}
fun observeForeverUnStick(observer: Observer<in T>) {
super.observeForever(NoStickWrapObserver(this, observer = observer))
}
fun removeObserverUnStick(observer: Observer<*>) {
requireMObservers().let { iter->
val foundList = ArrayList<Observer<in T>>()
for (entry in iter) {
val wrap = entry.key as? NoStickWrapObserver<*>
if (wrap != null && wrap.observer == observer) {
wrap.asOrNull<Observer<in T>>()?.apply {
foundList.add(this)
}
}
}
foundList.forEach {
super.removeObserver(it)
}
}
}
private class NoStickWrapObserver<D:Any>(val self:NoStickLiveData<D>,
val observer: Observer<in D>) : Observer<D> {
private val version: Int = self.mVersion //标记进入的时候的版本
override fun onChanged(value: D) {
if (version < self.mVersion) {
observer.onChanged(value)
}
}
}
}
2024/05/21修改:微调代码,并追加混淆规则,否则编译的时候,基础库被混淆了,这里就无法反射到mObservers:
-keep class androidx.lifecycle.** { *;}
众所周知,LiveData是粘性的。即,当liveData赋值过(或者初始化默认有值),则当监听observe的瞬间,立刻回调给你的监听函数。
想要破除粘性,我翻阅了一些代码,写的五花八门。我这边也是将我个人的实现方案写在这里。
仔细阅读liveData源码,关键点是mVersion三个变化:
- 空构造体赋值-1
- 有参数构造体赋值0
- 随后setValue每次++
而业务代码注册监听的函数observe(owner, observer) 或者observeForever(observer)
都是经过了包装,
LifecycleBoundObserver(owner, observer)
AlwaysActiveObserver(observer)
都放在了全局变量map,mObservers里面。key就是我们传入的变量observer。
直到removeObserver的时候,通过mObservers.remove(observer)来移除。
因此,类似的,我们只需要继承它,同时也借鉴:
- 也在setValue每次把自定义的版本号mVersion++以表征值的更新;
- 然后我们把用户代码的observe或者observeForever进行一次NoStickWrapObserver包装。只有当version有变大才通知即可;
- 移除的时候,就要考虑了。因为父类中mObservers存储的key,就是我们的NoStickWrapObserver,因此,我们需要将用户的observer,反射拿到父类对象map再找出我们的包装类,再去移除。
本代码的好处,
第一,反射只一次,因为mObservers在LiveData是final的全局变量,不会变化,性能损失可以忽略。
第二,与源代码LiveData的思想高度统一,通过wrap用户的observer存起来的思路。
第三,代码量极少;
第四,最重要的,你如果你想要原来的逻辑的LiveData就按照之前的写法;如果想注册一个后续监听的则调用observeUnStick即可,灵活且方便。