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.
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.
Traditionally, when something subscribes to something else, it is responsible for unsubscribing itself. You could do this by using an 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.temperatureChangedObservers.add(this) { temperature ->
println("Temperature changed: $temperature")
}
// remove self as observer when going out of scope:
weatherStation.temperatureChangedObservers.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.
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. 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")
}