简体   繁体   English

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

[英]Using “Delegates.observable” with list of Observers

This article shows one example code using multiple handlers in one observer. 本文展示了一个在一个观察者中使用多个处理程序的示例代码。 I give a code example from this article below.我在下面的这篇文章中给出了一个代码示例。 But there is a memory leak error in this code - the handler is added to the mutablelist, but it is not deleted from the list when, for example, an object using one of the handlers is deleted from memory.但是此代码中存在 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")
}

How to fix it, or are there alternative solutions?如何解决它,或者是否有替代解决方案? I need - so that when changing one property, several observers are invoked.我需要 - 这样在更改一个属性时,会调用多个观察者。 Trying to use LiveData causes a lot of difficulties .尝试使用 LiveData 会带来很多困难

Traditionally, when something subscribes to something else, it is responsible for unsubscribing itself.传统上,当某物订阅另一物时,它负责取消订阅自己。 You could do this by using an IdentityHashMap:您可以通过使用 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)

I used IdentityHashMap rather than a MutableMap or HashMap so we won't have to worry about the possibility of two different observers possibly having object-equality.我使用了 IdentityHashMap 而不是 MutableMap 或 HashMap,所以我们不必担心两个不同的观察者可能具有对象相等性的可能性。

If you want to automate unsubsribing, so you don't have to worry about it when your Fragment or Activity goes out of scope, you can require observers to be LifecycleOwners so you can observe their lifecycles.如果您想自动取消订阅,那么当您的 Fragment 或 Activity 超出 scope 时,您不必担心它,您可以要求观察者成为 LifecycleOwners,以便您可以观察它们的生命周期。 I didn't test this:我没有测试这个:

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")
}

Thanks for the answer to the Tenfour04.感谢您对 Tenfour04 的回答 I took his answer as a basis and made a simple universal class that maintains a list of observers.我以他的回答为基础,制作了一个简单的通用 class 维护观察者列表。 Class supports auto unsubsribing if the LifecycleOwner is used as a key.如果 LifecycleOwner 用作密钥,Class 支持自动退订。 This is a simple alternative to LiveData.这是 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