ProtectedUnPeekLiveData为什么不能直接持有Observer?
wl0073921 opened this issue · comments
如题,反正LiveData已经通过mObservers持有了Observer,再多一次持有也无所谓吧?
ProtectedUnPeekLiveData重写removeObserver()清理就好了嘛。
您可以先 fork 和提交您改进的代码,不然缺乏一致的前提依据来有效交流。
ProtectedUnPeekLiveData自持有observer及其proxy,在removeObserver(observer: Observer)时到observerProxyMap中获取相应的observer,而不是反射mObservers。
class ProtectedUnPeekLiveData : MutableLiveData() {
companion object {
private const val TAG = "ProtectedUnPeekLiveData"
}
// observer及其是否需要观察变化的映射
private val observerStateMap: ConcurrentHashMap<Observer<in T>, Boolean> = ConcurrentHashMap()
// observer及其代理的映射
private val observerProxyMap: ConcurrentHashMap<Observer<in T>, Observer<in T>> =
ConcurrentHashMap()
override fun observe(owner: LifecycleOwner, observer: Observer<in T>) {
getObserverProxy(observer)?.let {
super.observe(owner, it)
}
}
override fun observeForever(observer: Observer<in T>) {
getObserverProxy(observer)?.let {
super.observeForever(it)
}
}
private fun getObserverProxy(observer: Observer<in T>): Observer<T>? {
return if (observerStateMap.containsKey(observer)) { // 去重,owner相同时没意义,owner不相同时会crash
Log.d(TAG, "observe repeatedly, observer has been attached to owner")
null
} else {
observerStateMap[observer] = false
val proxy = ObserverProxy(observer)
observerProxyMap[observer] = proxy
proxy
}
}
private inner class ObserverProxy(observer: Observer<in T>) : Observer<T> {
private val target = observer
override fun onChanged(t: T) {
if (observerStateMap[target] == true) {
observerStateMap[target] = false
target.onChanged(t)
}
}
internal fun getTarget(): Observer<in T> {
return target
}
}
open fun observeSticky(owner: LifecycleOwner, observer: Observer<T>) {
super.observe(owner, observer)
}
open fun observeStickyForever(observer: Observer<T>) {
super.observeForever(observer)
}
override fun setValue(value: T) {
for (item in observerStateMap) {
item.setValue(true)
}
super.setValue(value)
}
/**
* 移除observer
* @param observer(业务侧触发时是Observer,LiveData内部触发时是ObserverProxy)
*/
override fun removeObserver(observer: Observer<in T>) {
val proxy: Observer<in T>?
val target: Observer<in T>?
if (observer is ObserverProxy) {
proxy = observer
target = observer.getTarget()
} else {
proxy = observerProxyMap[observer]
target = if (proxy != null) observer else null
}
if (proxy != null && target != null) {
observerProxyMap.remove(target)
observerStateMap.remove(target)
super.removeObserver(proxy)
}
}
}
感谢你的分享,刚刚测试了一番,上述代码的设计十分精妙,
对于非粘性的 observe 是当页面离开时即移除 observe,而粘性的 observe 则得以保留,
如此即使不使用反射,也能规避页面重建时,非粘性 observe 的重复创建和内存占用。
·
为此,可以邀请你 pull request 一稿上述的代码设计吗?(作为 V6 版)
上述设计使 UnPeek-LiveData 变得更好,开源并不是一个人的战斗,我们希望越来越多 “对开源项目作出过有效贡献的开发者” 出现在 Contributions 名单中。
(考虑到多数开发者阅读 Java 源码的需要,后续我们会翻译成 Java 代码,和基于 “唯一可信源” 理念对 setValue 等方法的访问权限做些微调。当然你若愿意主动翻译那更好了。)
你这边直接拿去用即可。另,我只是实现了我的一个想法,并没有充分测试哈,小心有坑!
好的,感谢,我们会在 v6 版源码中注明贡献者和出处。
逻辑比 V5 清晰了很多。
override fun postValue(value: T) {
for (item in observerStateMap) {
item.setValue(true)
}
super.postValue(value)
}
少了这个方法!