I'm having a problem with `rememberSaveable` input...
# compose-android
m
I'm having a problem with
rememberSaveable
inputs. I assumed it's meant to work just like
remember
keys or like
LaunchedEffect
keys where any change in any of the keys would trigger a re-calculation or re-run of the init block. But for some reason, it does't always run - it gives inconsistent results across different devices, and sometimes even on the same device. Take a look at this code below, why does the print statement in the
LaunchedEffect
and the
remember
block work, but not the
rememberSaveable
?
Copy code
val density = LocalDensity.current
    val d = density.density
    val f = density.fontScale

    println("Density: $d, Font Scale: $f")

    LaunchedEffect(d, f) {
        println("Screen density changed, resetting content height")
    }

    val testRememberHeight by remember(d, f) {
        println("Recalculating test height")
        mutableFloatStateOf(0f)
    }

    val contentHeightDp by rememberSaveable(d, f) {
        println("Recalculating content height")
        mutableFloatStateOf(0f)
    }
Am I doing something wrong? Perhaps the way I'm changing the density (using the Android Studio Emulator quick tools) isn't the correct way? Though I clearly see the logs printed indicating the Density and Scale changing.
I created a minimal sample that uses a button and a counter to act as the key for the
rememberSaveable
block. In that case, it always prints, so perhaps this has something to do with how the density is updated.
z
if the keys restart the other things, they should restart the
rememberSaveable
. Both
d
and
f
are primitive values, so shouldn't be anything weird here. This sounds like a bug to me
m
Gotcha! I’ll raise an issue for this and see what they say.
z
can you repro if you pass different
Density
instances at a higher level?
m
Thanks. I tried that and in the course of different combinations, I realised that changing density values are configuration changes, causing the Composable to be re-initialized, similar to switching between light mode and dark mode or rotating the screen. From what I can see,
rememberSaveable
is designed to execute it's calculation block during recomposition, but when config changes occur, it seems to favour restoring the last saved state, without factoring the inputs passed before the config change. I don't know if this is by design or a bug. So assuming I had something like:
Copy code
@Composable
fun TestCompose() {
    val isDark = isSystemInDarkTheme()

    println("Is Dark: $isDark")

    LaunchedEffect(isDark) {
        println("Theme changed: $isDark")
    }

    val testRememberHeight by remember(isDark) {
        println("Recalculating test height")
        mutableFloatStateOf(0f)
    }

    val contentHeightDp by rememberSaveable(isDark) {
        println("Recalculating content height")
        mutableFloatStateOf(0f)
    }
}
Switching themes will re-initialize the composable, and this causes
LaunchedEffect
and
remember
to print again, independent of the fact that the
isDark
boolean got toggled.
LaunchedEffect(Unit)
and
remember()
with no keys would do the same. However,
rememberSaveable
does nothing since its state has already been saved with a key and its value is simply restored, even though the input (which is tied to the config) was changed.
Et voilà! It's by design. Link
z
Ah nice