首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将"Delegates.observable“与观察者列表一起使用

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

Stack Overflow用户
提问于 2020-04-16 21:39:57
回答 2查看 488关注 0票数 0

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

代码语言:javascript
复制
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会导致大量的difficulties

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-04-16 22:26:05

传统上,当某个东西订阅了其他东西时,它负责取消订阅自己。您可以通过使用IdentityHashMap来完成此操作:

代码语言:javascript
复制
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,所以我们不必担心两个不同的观察者可能具有对象相等性。

如果你想自动取消订阅,这样当你的片段或活动超出范围时,你就不必担心了,你可以要求观察者是LifecycleOwners,这样你就可以观察他们的生命周期。我没有测试这个:

代码语言:javascript
复制
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")
}
票数 1
EN

Stack Overflow用户

发布于 2020-04-17 12:15:29

感谢您向Tenfour04发送answer!我以他的回答为基础,创建了一个维护观察者列表的简单通用类。如果将LifecycleOwner用作键,则类支持自动取消订阅。这是LiveData的一个简单替代方案。

代码语言:javascript
复制
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")
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61251720

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档