Josh Eldridge
03/23/2024, 4:25 AMrememberSaveable and how something is considered to leave composition. I'm a bit confused because a rememberSaveable value sticks around after device rotation, which makes sense. But in the scenario that the rememeberSaveable was part of an if/else, and "leaves" the composition on rotation, it's value is still preserved after its block is re-introduced. An example below I get into the if with a button click, add the value a few times, rotate the device (causing me to go back to the else) and click the Go to if the rememberSaveable value is still around, even though it left the composition while the composable was in the else?
Column {
var inIf by remember { mutableStateOf(false) }
if (inIf) {
var rememberTest by rememberSaveable { mutableIntStateOf(1) }
Timber.d(rememberTest.toString())
Button({
rememberTest += 1
}) {
Text("Do it $rememberTest times")
}
Button({
inIf = false
}) {
Text("Go to else")
}
} else {
Button({
inIf = true
}) {
Text("Go to if")
}
}
}Josh Eldridge
03/23/2024, 4:36 AMrememberSaveable to be freshly created if I rotated, it was outside the composition after rotation, and I brought it back into the composition through the conditionalAlex Vanyo
03/25/2024, 1:49 AMrememberSaveable works by storing the state of whatever is in composition when saved instance state is saved. Upon recreation, state starts getting restored back out of saved instance state - but it isn't required that the state be restored immediately in the first composition. The saved instance state will hang around until something pulls it back out.
So in this case, if inIf is true when rotating, the saved instance state of rememberTest will be saved. After recreation, where inIf is false, the saved instance state will remain available but nothing has consumed it yet. When inIf becomes true, now the saved instance state will be restored from before the recreation.
The rule is more like "`rememberSaveable` will lose its state when leaving composition unless the cause of leaving composition is due to the saved instance state being saved"Alex Vanyo
03/25/2024, 1:50 AMvar isLoading by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
delay(1000)
isLoading = true
}
if (isLoading) {
CircularProgressIndicator()
} else {
val myState by rememberSaveable { mutableStateOf(0) }
// ...
}Josh Eldridge
03/25/2024, 2:14 AMmovableContentOf to handle layout changes without having two separate composables with their own state. But this is helpful to know still.
Is there a way to know looking inside the rememberSaveable code to know how it would differentiate leaving composition normally vs from a configuration change aka saved instance state?
When I'm initially looking inside it I'm guessing maybe it maintains the same compositeKey on rotation vs normally leaving the composition it'd generate a new key and thus clear any saved state it was referring to?Alex Vanyo
03/25/2024, 2:24 AMrememberSaveable internally registers a provider to the LocalSaveableStateRegistry. When rememberSaveable leaves composition, it unregisters that provider. So from the perspective of rememberSaveable, it doesn't care about why it is leaving composition - it just registers and unregisters based on if it is in composition.
The resulting behavior is based on when LocalSaveableStateRegistry queries all of its providers to gather up saved instance state. When recreation happens, that query will happen before the providers get unregistered. When it is an `if`/`else` swapping whether rememberSaveable is in composition, there's no query to save the instance state, so it disappears.Josh Eldridge
03/25/2024, 3:26 AMrememberSaveable and I think I'm understanding better from your explanation. When I dug into it I had the "oh duh" moment because when switching between an if/else normally, the`rememberSaveable` isn't going to save anything off, it's only going to save something off from a config change or basically onSaveInstanceState right? So there is nothing for the registry to restore in the normal if/else, but in the case of the rotation, that registry still had that value and going back into the if makes this "new" rememberSaveable consume that restored valueJosh Eldridge
03/25/2024, 3:32 AMrememberSaveable 's in order to put them back into the correct order, and it seems like that key is always the same like you said. I'm guessing this is the important piece to tying them back to the same rememberSaveable calls? It uses the order of the calls to essentially make a queue for each rememberSaveable to call.Alex Vanyo
03/25/2024, 3:33 AMJosh Eldridge
03/25/2024, 3:36 AMAlex Vanyo
03/25/2024, 3:37 AM