![](/img/trans.png)
[英]Using Delegates.observable with StateFlow in Kotlin(Android)
[英]Using “Delegates.observable” with list of Observers
本文展示了一个在一个观察者中使用多个处理程序的示例代码。 我在下面的这篇文章中给出了一个代码示例。 但是此代码中存在 memory 泄漏错误 - 处理程序已添加到可变列表中,但不会从列表中删除,例如,使用其中一个处理程序的 object 从 ZCD69B4957F06CD818D7ZBF3D6198 中删除
class WeatherStation {
val temperatureChanged = mutableListOf<(Int) -> Unit>()
var temperature: Int by Delegates.observable(0) { _, _, newValue ->
temperatureChanged.forEach{it(newValue)}
}
}
// ...
val weatherStation = WeatherStation()
// Adding observer to the list, but where is its removal???
weatherStation.temperatureChanged.add { temperature ->
println("Temperature changed: $temperature")
}
如何解决它,或者是否有替代解决方案? 我需要 - 这样在更改一个属性时,会调用多个观察者。 尝试使用 LiveData 会带来很多困难。
传统上,当某物订阅另一物时,它负责取消订阅自己。 您可以通过使用 IdentityHashMap 来做到这一点:
class WeatherStation {
val temperatureChangedObservers = IdentityHashMap<Any, (Int) -> Unit>()
var temperature: Int by Delegates.observable(0) { _, _, newValue ->
temperatureChangedObservers.values.forEach { it(newValue) }
}
}
// ...
val weatherStation = WeatherStation()
weatherStation.temperatureChanged.add(this) { temperature ->
println("Temperature changed: $temperature")
}
// remove self as observer when going out of scope:
weatherStation.remove(this)
我使用了 IdentityHashMap 而不是 MutableMap 或 HashMap,所以我们不必担心两个不同的观察者可能具有对象相等性的可能性。
如果您想自动取消订阅,那么当您的 Fragment 或 Activity 超出 scope 时,您不必担心它,您可以要求观察者成为 LifecycleOwners,以便您可以观察它们的生命周期。 我没有测试这个:
class WeatherStation: LifecycleObserver {
private val temperatureChangedObservers = IdentityHashMap<LifecycleOwner, (Int) -> Unit>()
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onObserverDestroyed(source: LifecycleOwner) {
temperatureChangedObservers.remove(source)
}
fun observeTemperature(observer: LifecycleOwner, action: (Int) -> Unit) {
temperatureChangedObservers[observer] = action
observer.lifecycle.addObserver(this)
}
var temperature: Int by Delegates.observable(0) { _, _, newValue ->
temperatureChangedObservers.values.forEach { it(newValue) }
}
}
// ...
val weatherStation = WeatherStation()
weatherStation.observeTemperature(this) { temperature ->
println("Temperature changed: $temperature")
}
感谢您对 Tenfour04 的回答。 我以他的回答为基础,制作了一个简单的通用 class 维护观察者列表。 如果 LifecycleOwner 用作密钥,Class 支持自动退订。 这是 LiveData 的简单替代方案。
class Visor<T>(initialValue: T): LifecycleObserver {
private var value = initialValue
private val observers = WeakHashMap<Any, (T) -> Unit>()
fun subscribe(owner: Any, observer: (T) -> Unit) {
if (owner is LifecycleOwner)
owner.lifecycle.addObserver(this)
observers[owner] = observer
}
fun subscribeAndInvoke(owner: Any, observer: (T) -> Unit) {
add(owner, observer)
observer(value) // invoke
}
fun remove(key: Any) {
observers.remove(key)
}
@OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
fun onObserverDestroyed(owner: LifecycleOwner) {
remove(owner)
}
operator fun getValue(thisRef: Any?, prop: KProperty<*>): T = value
operator fun setValue(thisRef: Any?, prop: KProperty<*>, value: T) {
this.value = value
observers.values.forEach{it(value)} // invoke all observers
}
}
// example of using
class WeatherStation() {
var temperatureVisor = Visor<Int>(0)
var temperature: Int by temperatureVisor
// ...
}
// addition of the first observer
val weatherStation = WeatherStation()
weatherStation.temperatureVisor.subscribe(this) {
Log.d("Visor", "New temperature: $it")
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.