使用 "Delegates.observable" 和观察者列表

Using "Delegates.observable" with list of Observers

article 显示了在一个观察者中使用多个处理程序的示例代码。我在下面的这篇文章中给出了一个代码示例。但是此代码中存在内存泄漏错误 - 处理程序已添加到可变列表中,但未从列表中删除,例如,使用其中一个处理程序的对象已从内存中删除。

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 超出范围时你就不必担心它,你可以要求观察者成为 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! 我以他的回答为基础,做了一个简单的 universal class 来维护一个观察者列表。 Class 如果将 LifecycleOwner 用作密钥,则支持自动取消订阅。 这是 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")
}