Hi everyone! I ran into a problem with using `reme...
# compose
k
Hi everyone! I ran into a problem with using
rememberSaveable
inside
SaveableStateHolder.SaveableStateProvider
: rememberSaveable loses data when composable hierarchy changes. I provided the example to reproduce behavior which contains either correct and incorrect version, but if you use both composables simultaneously, correct version brakes.
a
@param key An optional key to be used as a key for the saved value. If not provided we use the automatically generated by the Compose runtime which is unique for the every exact code location in the composition tree
The default keys will be different for separated invocations. If you want to restore the same value, you should provide the same
key
manually.
k
but
rememberSaveable
is called inside
SaveableStateProvider
and I’ve already provided key for
SaveableStateProvider
.
Documentation sais
Copy code
/**
 * Allows to save the state defined with [rememberSaveable] for the subtree before disposing it
 * to make it possible to compose it back next time with the restored state. It allows different
 * navigation patterns to keep the ui state like scroll position for the currently not composed
 * screens from the backstack.
 *
 * @sample androidx.compose.runtime.saveable.samples.SimpleNavigationWithSaveableStateSample
 *
 * The content should be composed using [SaveableStateProvider] while providing a key representing
 * this content. Next time [SaveableStateProvider] will be used with the same key its state will be
 * restored.
 */
interface SaveableStateHolder {
    /**
     * Put your content associated with a [key] inside the [content]. This will automatically
     * save all the states defined with [rememberSaveable] before disposing the content and will
     * restore the states when you compose with this key again.
     *
     * @param key to be used for saving and restoring the states for the subtree. Note that on
     * Android you can only use types which can be stored inside the Bundle.
     */
    @Composable
    fun SaveableStateProvider(key: Any, content: @Composable () -> Unit)
a
unique for the every exact code location in the composition tree
It maybe a little bit hard to understand but the
ScreenContent
calls are different so they are not in the same location in the composition tree. And I mean provide a
key
for
rememberSaveable
.
k
@Albert Chang you can ez check, that passing key to rememberSaveable doesn’t solve the problem
Copy code
val background = rememberSaveable(key = id) { Random.nextInt() }
a
Then you should file a bug.
a
when you conditionally emit the same composable differently (in Row in one case and without anything in another one) you need to use moveableContentOf as otherwise we can’t understand that you consider those invocations as the same one in order to move their state properly when the condition is changed
k
I supposed that remember saveable depends from nearest
SaveableStateProvider
(which provides some composition local under the hood), but not from placement in hierarchy. Documentation says
Copy code
* The content should be composed using [SaveableStateProvider] while providing a key representing
 * this content. Next time [SaveableStateProvider] will be used with the same key its state will be
 * restored.
a
yes, but the keys for the rememberSaveables within the subhierarchy are calculated as a combination of all the keys for the composable calls stack. which means that rememberSaveable of ScreenContent used in the new place will have a different key and can’t restore the state
moveableContentOf allows to avoid that