https://kotlinlang.org logo
#getting-started
Title
# getting-started
s

Sam Stone

03/22/2023, 4:43 PM
I am trying to make an observable list, where I have a LiveData/StateFlow that emits the list whenever the list is mutated. I need the list to be iterable by multiple threads/coroutines. This is my signature:
Copy code
class ObservableList<T>: MutableList<T> by Collections.synchronizedList(ArrayList()) {
But when I override a function, it gives an error: Abstract member cannot be accessed directly
Copy code
override fun add(element: T): Boolean {
    val add = super.add(element)
    mObserver.postValue(this)
    return add
}
s

Sam

03/22/2023, 4:45 PM
e

ephemient

03/22/2023, 4:46 PM
you want to delegate to the
Collections.synchronizedList()
value, not
super
s

Sam Stone

03/22/2023, 4:55 PM
@ephemient so
this
?
e

ephemient

03/22/2023, 4:56 PM
no, that just leads to recursion
Copy code
class ObservableList<T>(private val delegate = Collections.synchronizedList(ArrayList())) : MutableList<T> by delegate {
    override fun add(element: T): Boolean {
        delegate.add(element)
    }
}
s

Sam Stone

03/22/2023, 4:57 PM
Right. Thanks! And is `synchronizedList`the way to solve my issue?
e

ephemient

03/22/2023, 4:59 PM
the values posted to the observer may be in a different order than the values added to the list
s

Sam Stone

03/22/2023, 5:02 PM
What about in this class?
Copy code
class Observable<T>() {
    constructor(initialValue: T) : this() {
        state.value = initialValue
    }

    private val state = MutableStateFlow<T?>(null)
    var value: T
        get() = state.value!!
        set(value) { state.value = value }

    private val observers = Collections.synchronizedList(mutableListOf<suspend (T) -> Unit>())
    fun observe(observer: suspend  (T) -> Unit) {
        val suspendNullable: suspend (T?) -> Unit = { it?.let { it1 -> observer(it1) } } //don't want to expose that we use nulls internally
        observers.add(suspendNullable)
        appScope.launch {
            state.collect(suspendNullable)
        }
    }

    fun removeObserver(observer: suspend (T) -> Unit) {
        observers.remove(observer)
    }
}
e

ephemient

03/22/2023, 5:04 PM
you don't care about the order in that case
s

Sam Stone

03/22/2023, 5:05 PM
What do you mean?
e

ephemient

03/22/2023, 5:08 PM
Copy code
thread 1:           thread 2:
observe(f) {        observe(g) {
  observers.add(f)
                      observers.add(g)
                      scope.launch()
  scope.launch()
}                   }
that can happen, the same as in your previous version (just the other way around)
s

Sam Stone

03/22/2023, 5:10 PM
Is that a potential concern? If I am relying on the internal data structure to match what the observer was told, will the app potentially crash because of the discrepancy?
e

ephemient

03/22/2023, 5:11 PM
I can't tell what your app logic will do with it. but hopefully you don't care about observer order
s

Sam Stone

03/22/2023, 5:13 PM
I think I get it. So I shouldn’t rely on the current observer being reflective of what is stored in memory, because a new event might be published/the observer will soon be notified of a new change?
s

sciack

03/23/2023, 5:24 AM
Maybe is better a
CopyOnWriteArrayList
248 Views