Search code examples
android-jetpack-composeandroid-jetpack-compose-lazy-column

Composable state is lost after scroll and rotation


I have a LazyColumn containing ToggleButtonGroups that I have created myself. My issue can be reproduced by these three steps:

  1. Select "YES" on every ToggleButtonGroup Image A

  1. Rotate the screen and then scroll to the bottom Image B

  1. Rotate the screen back. Now, the topmost three to four ToggleButtonGroups are reset. Image C

The problem does not appear if I don't scroll after rotating. So by rotation alone, the state is saved properly, as I would have expected it by using rememberSaveable.

The code is provided below:

 LazyColumn() {

        items(characteristics) {characteristic: Characteristic ->

            ToggleButtonGroup(
                defaultIndex = 2,
                values = listOf(Pair("YES", -1), Pair("NO", 1), Pair("TBD", 0)),
                onToggleChange = { newValue: Int ->
                    characteristic.value = newValue
                }
            )
        }
    }

The Composable named ToggleButtonGroup is seen below:

@Composable
fun ToggleButtonGroup(defaultIndex: Int, values: List<Pair<String, Int>>, onToggleChange: (newValue: Int) -> Unit) {

    var selectedIndex by rememberSaveable {
        mutableStateOf( defaultIndex.coerceIn(0, values.size - 1) )
    }

    Row(
        modifier = Modifier.wrapContentHeight()
    ) {

        values.forEachIndexed { index: Int, value: Pair<String, Int> ->

            FilledTonalButton(
                colors = if (selectedIndex == index) ButtonDefaults.buttonColors() else ButtonDefaults.filledTonalButtonColors(),
                onClick = { selectedIndex = index; onToggleChange(value.second) },
                shape = RectangleShape
            ) {
                Text(text = value.first)
            }
        }
    }
}

And the characteristics data is coming from my ViewModel:

data class Characteristic(val title: String, val weight: Int, var value: Int)
var characteristics by mutableStateOf(listOf<Characteristic>())

Thank you for any efforts!


Solution

  • It seems like this is an intended behaviour. There is an issue open on the Google Issue Tracker which describes a similar problem. The issue was marked as "intended behaviour", as this mechanism of releasing the state of non-visible items at rotation was introduced with this commit:

    Save the states only for the currently visible items of lazy layouts

    When we save the state of the screen in cases like navigation to other screen or activity rotation we were saving the state for all items which were ever visible in the lazy layouts like LazyColumn. We want to save state while user is scrolling so they not lose it when they scroll back, however when this screen is not active anymore keeping the states for all items is not efficient as we easily can fill up the whole available limit provided by the Bundle. Instead it could be reasonable to only save states for the items which were visible when the screen state save happens.