繁体   English   中英

将“Delegates.observable”与观察者列表一起使用

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM