theapache64
05/09/2022, 8:24 AM@Composable
fun MyComposable(
viewModel: MyViewModel = hiltViewModel()
) {
Text(text = viewModel.myState)
}
class MyViewModel : ViewModel() {
var myState by mutableStateOf("A")
private set
init {
viewModelScope.launch(<http://Dispatchers.IO|Dispatchers.IO>) {
myState = "B"
}
}
}
The above code (myState= “B”) will crash the app saying
Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied
PS: I read this thread but I don’t fully understand “why” the runtime had to throw that crash? Why it can’t handle the scenario gracefully ? Maybe update the UI with the new state (“B”)? And does it only happen during composition?Filip Wiesner
05/09/2022, 8:33 AMtheapache64
05/09/2022, 10:12 AMFilip Wiesner
05/09/2022, 10:21 AMAdam Powell
05/09/2022, 2:33 PMLaunchedEffect
and similar, or use of `stateIn(..., SharingStarted.WhileSubscribed(), ...)`; the viewmodel itself is generally inert unless acted on from outsideFilip Wiesner
05/09/2022, 2:51 PMThe problem is that you are changing a state that is not yet managed by any snapshot and the history of these changes cannot be "saved" anywhere.I might have it from some of Zachs articles about State but I am not sure if I remember it correctly.
Adam Powell
05/09/2022, 2:58 PMthis
of a non-final class during construction; non-null things can be observed to be null, writes will be overwritten when the real constructor actually runs, lots of bad timesFilip Wiesner
05/09/2022, 3:08 PMAdam Powell
05/09/2022, 3:11 PMFilip Wiesner
05/09/2022, 3:13 PMAdam Powell
05/09/2022, 3:23 PMManideep Polireddi
05/09/2022, 3:28 PMAdam Powell
05/09/2022, 3:29 PMManideep Polireddi
05/09/2022, 3:33 PMAndroidRuntime: java.lang.IllegalStateException: Reading a state that was created after the snapshot was taken or in a snapshot that has not yet been applied
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.runtime.snapshots.SnapshotKt.readError(Snapshot.kt:1646)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.runtime.snapshots.SnapshotKt.readable(Snapshot.kt:1641)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.runtime.snapshots.SnapshotKt.readable(Snapshot.kt:1632)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.runtime.SnapshotMutableStateImpl.getValue(SnapshotState.kt:130)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.animation.core.AnimationScope.isRunning(AnimationState.kt:337)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.animation.core.SuspendAnimationKt.animate(SuspendAnimation.kt:260)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.animation.core.SuspendAnimationKt$animate$4.invokeSuspend(Unknown Source:17)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.ui.platform.AndroidUiDispatcher.performTrampolineDispatch(AndroidUiDispatcher.android.kt:81)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.ui.platform.AndroidUiDispatcher.access$performTrampolineDispatch(AndroidUiDispatcher.android.kt:41)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at androidx.compose.ui.platform.AndroidUiDispatcher$dispatchCallback$1.doFrame(AndroidUiDispatcher.android.kt:68)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1278)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.view.Choreographer.doCallbacks(Choreographer.java:1019)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.view.Choreographer.doFrame(Choreographer.java:907)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1248)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.os.Handler.handleCallback(Handler.java:900)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:103)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.os.Looper.loop(Looper.java:219)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:8668)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:513)
05-06 20:37:22.524 17381 17381 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1109)Filip Wiesner
05/09/2022, 3:44 PMAdam Powell
05/09/2022, 5:39 PMmutableStateOf
as a key into a map held by the snapshot system. Reading or writing the value with that key will fail if you try to do it before the key is in the map, which doesn't happen until the snapshot where the key was created is committedFilip Wiesner
05/09/2022, 5:46 PMAdam Powell
05/09/2022, 5:47 PMFilip Wiesner
05/09/2022, 5:52 PMbecause if you are doing it from a main thread, the snapshot is already appliedIf we use the
Main.immediate
dispatcher (viewModelScope
) in the init
block, the State could still be read before the snapshot is applied. If I understand it correctly, the Main.immediate
dispatcher does not schedule the job to the end of the queue but executes it immediately if already on main thread.Adam Powell
05/10/2022, 2:30 PMManideep Polireddi
05/10/2022, 2:32 PMFilip Wiesner
05/10/2022, 4:34 PMZach Klippenstein (he/him) [MOD]
05/13/2022, 2:50 PMMutableState
work, if you’re looking for a longer explanation: https://dev.to/zachklipp/implementing-snapshot-aware-data-structures-3pi8