Jetpack Compose中remember作用及选中状态首次重置问题解析
问题分析与解答
问题描述
我想让selectedProvince的状态持久化,于是用remember包裹它,但每次在onClick修改值后,Compose重组时这个变量会被重置为listProvince.value[0](仅首次出现),原本以为它会保留最后选中的值。后来用mutableStateOf解决了问题,但不清楚原理,同时想了解Jetpack Compose中remember关键字的作用。
原代码
@Composable fun ProvinceDialog( modifier: Modifier = Modifier, listProvince: MutableState<List<ProvinceItem>>, onDisMiss: () -> Unit = {}, onConfirm: (String) -> Unit = {} ) { val searchText = remember { mutableStateOf("") } var selectedProvince = remember { mutableStateOf(listProvince.value[0]) } Log.d("Test select", selectedProvince.toString()) AlertDialog( modifier = modifier, title = { Text(text = "Province") }, containerColor = EDSColors.white, text = { Column( modifier = Modifier .fillMaxSize() .padding(16.dp), verticalArrangement = Arrangement.spacedBy(8.dp) ) { OutlinedTextField( value = searchText.value, onValueChange = { searchText.value = it }, leadingIcon = { Icon(imageVector = Icons.Default.Search, contentDescription = null) }, singleLine = true, shape = RoundedCornerShape(30), colors = OutlinedTextFieldDefaults.colors( cursorColor = EDSColors.primaryColor, focusedBorderColor = EDSColors.primaryColor, focusedLeadingIconColor = EDSColors.primaryColor, ), ) LazyColumn( verticalArrangement = Arrangement.spacedBy(8.dp) ) { listProvince.value.forEachIndexed { index, province -> item { FilterChip( modifier = Modifier.fillMaxWidth(), selected = province.isSelected, onClick = { val newList = listProvince.value.toMutableList() newList.forEach { it.isSelected = false } newList[index] = province.copy(isSelected = !province.isSelected) selectedProvince.value = newList[index] Log.d("Test select", selectedProvince.toString()) listProvince.value = newList }, label = { Text( province.provinceName, fontWeight = FontWeight.W300, maxLines = 1, overflow = TextOverflow.Ellipsis, modifier = Modifier .fillMaxWidth(.85f) ) }, trailingIcon = { if (province.isSelected) Icon( imageVector = Icons.Default.CheckCircle, contentDescription = null ) }, colors = FilterChipDefaults.filterChipColors( selectedContainerColor = EDSColors.greenCheck, selectedLabelColor = EDSColors.white, selectedTrailingIconColor = EDSColors.white ) ) } } } } }, onDismissRequest = { onDisMiss() }, confirmButton = { TextButton(onClick = { onConfirm( selectedProvince.value.provinceName ) }) { Text("Accept", color = EDSColors.primaryColor) } }, dismissButton = { TextButton( onClick = { onDisMiss() } ) { Text("Dismiss", color = EDSColors.notScheduleTextColor) } } ) }
为什么初始写法会出现状态重置?
你最初的写法如果是仅用var selectedProvince = remember { listProvince.value[0] }(未包装mutableStateOf),就会出现状态重置:
remember的初始化逻辑仅在Composable首次组合时执行一次,后续重组直接返回首次保存的初始值。- 直接修改
selectedProvince不会触发Compose感知状态变化,当listProvince更新触发重组时,remember会返回首次保存的listProvince.value[0],看起来像是状态被重置。 - 改用
mutableStateOf后,selectedProvince变成可观察的State对象,修改selectedProvince.value会触发Compose重组,同时remember持续保存这个MutableState实例,确保状态在重组时不丢失。
Jetpack Compose中remember的作用
- 核心功能:在Composable重组时保留状态。Composable会因状态变化反复执行(重组),没有
remember的话,局部变量会在每次重组时重新初始化,状态完全丢失。 - 执行逻辑:首次组合时运行传入的初始化代码,将结果存入Compose状态容器;后续重组直接返回存储的值,不会重新执行初始化逻辑。
- 注意事项:
remember保存的是对象引用,如果是可变对象,必须用MutableState(如mutableStateOf)包装,才能让Compose感知状态变化并触发重组。remember的作用范围仅限当前Composable及其子Composable,当Composable从Composition中移除(比如弹窗关闭),保存的状态会被销毁。
内容的提问来源于stack exchange,提问作者Onii-Chan
相关产品推荐
相关产品推荐

