You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

滚动与旋转后Jetpack Compose组件状态丢失问题求助

问题分析与解决方案

问题根源

  1. 状态与数据不同步:ToggleButtonGroup内部用rememberSaveable维护选中状态,但初始化依赖固定的defaultIndex=2,没有和ViewModel中Characteristic的value绑定。当Composable重建或被LazyColumn复用时,会错误重置状态。
  2. LazyColumn复用逻辑问题:未给items指定唯一key,LazyColumn会基于item的位置或equals判断是否复用组件,导致状态和当前item数据不匹配。
  3. 数据更新未触发重组:Characteristic的value是可变属性,修改它不会触发mutableStateOf<List<Characteristic>>的重组,因为列表引用未变,UI无法感知数据变化。

解决方案

1. 状态提升:让ViewModel完全控制选中状态

将ToggleButtonGroup的选中状态改为外部传入,内部仅负责UI渲染和回调,消除本地状态与ViewModel数据的不一致:

@Composable
fun ToggleButtonGroup(
    selectedIndex: Int,
    values: List<Pair<String, Int>>,
    onToggleChange: (newValue: Int) -> Unit
) {
    val safeSelectedIndex = selectedIndex.coerceIn(0, values.size - 1)

    Row(modifier = Modifier.wrapContentHeight()) {
        values.forEachIndexed { index, value ->
            FilledTonalButton(
                colors = if (safeSelectedIndex == index) ButtonDefaults.buttonColors() else ButtonDefaults.filledTonalButtonColors(),
                onClick = { onToggleChange(value.second) },
                shape = RectangleShape
            ) {
                Text(text = value.first)
            }
        }
    }
}

2. 为LazyColumn指定唯一key

确保每个item拥有独立的组件实例,避免错误复用:

LazyColumn() {
    items(characteristics, key = { it.title }) { characteristic ->
        ToggleButtonGroup(
            // 根据ViewModel中的value映射到对应的选中索引
            selectedIndex = when (characteristic.value) {
                -1 -> 0 // YES
                1 -> 1 // NO
                0 -> 2 // TBD
                else -> 2
            },
            values = listOf(Pair("YES", -1), Pair("NO", 1), Pair("TBD", 0)),
            onToggleChange = { newValue ->
                viewModel.updateCharacteristicValue(characteristic.title, newValue)
            }
        )
    }
}

3. 修正ViewModel的数据更新逻辑

将Characteristic的value改为不可变属性,通过copy更新列表触发重组:

// ViewModel中修改数据定义与更新方法
data class Characteristic(val title: String, val weight: Int, val value: Int)
var characteristics by mutableStateOf(listOf<Characteristic>())

fun updateCharacteristicValue(title: String, newValue: Int) {
    characteristics = characteristics.map {
        if (it.title == title) it.copy(value = newValue) else it
    }
}

原理说明

通过状态提升,把UI状态完全托管给ViewModel,确保旋转、滚动等操作后,UI始终和ViewModel的数据保持一致。指定唯一key让LazyColumn能正确识别每个item,避免组件复用导致的状态混乱。不可变数据+列表引用更新则保证了数据变化能及时触发UI重组。

内容的提问来源于stack exchange,提问作者BenjyTec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:10:23