I was recently <surprised to learn> that `MutableS...
# compose
m
I was recently surprised to learn that
MutableState.value
should only be set on the UI/Main thread. Is this also true for
MutableStateList.add
?
s
That's not true, you want to make sure you don't mutate it from multiple threads at the same time, but that's about it. It can break if you update in from both UI thread and background threads though.
(break = crash at runtime with a snapshot apply exception)
s
If you wrap the sets inside a
Sanpshot.withMutableSnapshot
, will the crash at least be prevented, with the last one applying "winning" or will it crash then too?
s
To prevent the crash, you need to provide a mutation policy, so the state knows how to merge concurrent changes. Snapshots only guarantee local consistency, and will still crash by default if the state was modified outside the snapshot
m
@shikasd do you mean it’s not true for the
MutableState.value
or for the
MutableStateList.add
? Also, the view model is updating the mutable state in a suspend function, then wouldn’t doing something like
withContext(Dispatchers.Main)
be a good way to ensure “you don’t mutate it from multiple threads at the same time”?
s
It is true for both, since list is backed by the same mechanism. Technically, mutating all states on main thread is the safest option, but you do have other ways I outlined above (e.g. mutation policy)
👍 1
o
So does that mean that mutating state on multiple threads safely requires both, • (a) supplying a mutation policy, and • (b) using
Snapshot.withMutableSnapshot
? There's still that warning in the docs, which unfortunately does not provide sufficient details:
Warning: Updating Compose state from a non UI thread without using
Snapshot.withMutableSnapshot{ }
may cause inconsistencies in the state produced.
Also discussed here: https://kotlinlang.slack.com/archives/CJLTWPH7S/p1712221343758939?thread_ts=1712066552.382059&amp;cid=CJLTWPH7S
s
Only a), b) is required when you want transaction semantics when updating multiple states
Note that states don't really handle backpressure, so you cannot rely on it getting a sequence of events It will invalidate eventually with the latest value, but you might lose intermediate updates
o
Thanks for clarifying and yes, that’s what I was expecting. However, it seems that I have been observing a situation where Compose was not updating to the latest value. I‘ll try to reproduce this in simpler setup and file an issue. But this week it’s KotlinConf first. 🙂