I'm trying to make SaveableStateProvider work - I ...
# compose
z
I'm trying to make SaveableStateProvider work - I have Parcelable immutable data classes as keys (so hashCode/equals) and ensure SavedStateProviders exist while the keys are added, yet I'm still losing the saved state. What am I missing?
Copy code
Layout(
                content = {
                    allKeys.fastForEach { key ->
                        key(key) {
                            saveableStateHolder.SaveableStateProvider(key = key) {
                                if (key == topNewKey || (isAnimating && key == initialNewKey)) {
                                    Box(
                                        modifier = when {
                                            !isAnimating || initialization -> modifier
                                            else -> when {
                                                key == topNewKey -> newTransition.animateComposable(modifier, stateChange, fullWidth, fullHeight, animationProgress)
                                                else -> previousTransition.animateComposable(modifier, stateChange, fullWidth, fullHeight, animationProgress)
                                            }
                                        }
                                    ) {
                                        key.RenderComposable(modifier)
                                    }
                                }
                            }
                        }
                    }
                },
                measurePolicy = measurePolicy,
            )
^ theoretically I would think that
SaveableStateProvider
should store stuff in the "local saved state registry" which as I do not supply a custom one, should be the Activity
why would it lose state as I navigate forward? 🤔
or i should just give up on making
rememberSaveable
work, although that sounds not ideal
🤔
a
Copy code
@Immutable
@Parcelize
class SecondKey: ComposeKey() {
    @Composable
    override fun ScreenComposable(modifier: Modifier) {
        SecondScreen(modifier)
    }
}
is it how you define your keys?
z
yep
so
Copy code
@Immutable
@Parcelize
data class DogListKey(private val noArgPlaceholder: String = "") : ComposeKey() {
    @Suppress("RemoveExplicitTypeArguments")
    override fun bindServices(serviceBinder: ServiceBinder) {
        super.bindServices(serviceBinder)
        with(serviceBinder) {
            add(DogListViewModel(lookup<DogDataSource>()))
        }
    }

    @Composable
    override fun ScreenComposable(modifier: Modifier) {
        val viewModel = rememberService<DogListViewModel>()

        val dogs = viewModel.dogList.subscribeAsState(OptionalWrapper.absent())

        DogListScreen(dogs.value.value)
    }
}
a
you said the state is lost when you navigate forward? what does it mean? so you are on DogListKey screen, then you open another one while the list screen is in the backstack and then go back to the list screen?
z
yep
the LazyList starts at the top again 🤔
*LazyColumn i mean
i figured adding the savedStateProvider would help, but it didn't, even though i know that LazyColumn remembers the lazy scroll state and should therefore rely on the Saver to restore it
although now that i think about it, i should probably try this with a standard "Text" component to see if subcomposition has something to do with it 👀
a
so I tested your sample and you almost did it correct
aside from the ordering
here you need to first have
if (key == topNewKey || (isAnimating && key == initialNewKey))
and only then
saveableStateHolder.SaveableStateProvider(key = key)
why: because when you stop displaying the previous screen after the animation is finished SaveableStateProvider should also be disposed so the state is saved. if you have it before if the provider is still alive and knows nothing about the screen not being displayed anymore
z
oooh so it has to get detached to save, it's kinda the opposite than i thought (because for ensuring the composeHash to be the same, i had to make sure stuff is stable and alive), thanks for info i'll check it out 👍
a
rememberSaveableStateHolder() should be called outside of it so it stays active, but the separate providers on it should have the same lifecycle as the screens
z
amazing, it really does work now, thank you 🥳 🥳 🥳