I have a map, in my case a ConcurrentHashMap<String, Device>
which is updating when receiving some events on websocket. I want to implement an observable on this map to know when an entry is added, updated or deleted. I tried with an ObservableProperty
but no methods are called when map is changed.
var deviceCache : ConcurrentHashMap<String, Device> by MyObservable(ConcurrentHashMap())
class MyObservable<T, V>(initialValue: ConcurrentHashMap<T, V>) : ObservableProperty<ConcurrentHashMap<T, V>>(initialValue) {
override fun afterChange(property: KProperty<*>, oldValue: ConcurrentHashMap<T, V>, newValue: ConcurrentHashMap<T, V>) {
super.afterChange(property, oldValue, newValue)
log.e("new value is $newValue")
}
override fun beforeChange(property: KProperty<*>, oldValue: ConcurrentHashMap<T, V>, newValue: ConcurrentHashMap<T, V>): Boolean {
log.e("beforeChange called")
return super.beforeChange(property, oldValue, newValue)
}
}
Can anyone help me how can I solve this?
The problem is that Map
is not a property, you can't use property delegates this way. What you have to do is to write a decorator for Map
like this:
class ObservableMap<K, V>(private val map: MutableMap<K, V>) : MutableMap<K, V> by map {
override fun put(key: K, value: V): V? {
TODO("not implemented")
}
override fun putAll(from: Map<out K, V>) {
TODO("not implemented")
}
override fun remove(key: K): V? {
TODO("not implemented")
}
}
Here we delegate all operations to the backing map
and you just only have to implement your logic when adding/deleting in the methods above.
I'm not sure what you mean by update
but if you mean "a value in the map gets overwritten" than you can handle it in put
.
You can use this ObservableMap
like this:
val map = ObservableMap(ConcurrentHashMap<String, String>())
Note that if you want to support the operations of ConcurrentHashMap
you also need to include overrides
for AbstractMap<K,V>
and ConcurrentMap<K,V>
since they add some new operations you might want to track. The code above is just an example.