ursus
03/07/2021, 4:23 PMDispatcher.Main
ViewModel has state, and therefore State (MutableStateFlow<State>
) should only be set on main thread -- to avoid synchronization
Is there a way I can assert Scope is on main thread without an android reference? (Looper.myLooper() != Looper.getMainLooper()
)
(To keep my viewmodels KMP ready)
Or, should I just not care and read-write (reduce) to StateFlow within a synchronization block?Adam Powell
03/07/2021, 4:35 PMursus
03/07/2021, 4:39 PMfun <T> MutableStateFlow<T>.set(reduce: T.() -> T) {
synchronized(this) {
value = value.reduce()
}
}
fun ViewModel.someButtonClick() {
setState {
copy(counter = counter + 1)
}
}
Adam Powell
03/07/2021, 4:43 PMursus
03/07/2021, 4:45 PMprivate fun updateState(expectedState: Any?, newState: Any): Boolean {
var curSequence = 0
var curSlots: Array<StateFlowSlot?>? = this.slots // benign race, we will not use it
synchronized(this) {
val oldState = _state.value
if (expectedState != null && oldState != expectedState) return false // CAS support
...
or is that its just a "little bit" of synchronization so its okay?Adam Powell
03/07/2021, 4:52 PMursus
03/07/2021, 4:53 PMfun ViewModel.someButtonClick() {
synchronized(this) {
val currentValue = _state.value
_state.value = currentValue.copy(counter = counter + 1)
}
}
Or only if synchronized
swapped for CAS?Adam Powell
03/07/2021, 6:24 PMursus
03/07/2021, 6:34 PMAdam Powell
03/07/2021, 6:39 PMursus
03/07/2021, 6:49 PMScoped
types, which means such type has lifecycle (init, close) and holds state
In this sense viewmodel is just a common name for such Scoped subclass which just happens to be close to the ui
And the whole app is just a composition of Scoped instances (Lego bricks)
However one thing, why I mandated the main thread state access in viewmodels, was that, people seem to prefer imperatively accessing state like this
fun buttonClick() {
val state = _state.value
if (state.whatever) return
if (state.somethingElse) {
...
}
}
Which is nice and readable and very natural for most people. Same reason why I migrated of rx to coroutines -- to give me the language constructs as the apiAdam Powell
03/07/2021, 6:50 PMursus
03/07/2021, 6:51 PM