Jetpack Compose修改List值后UI不更新,如何解决?
问题:Jetpack Compose中LazyVerticalGrid无法随State更新UI
我在Jetpack Compose项目中制作了一个包含3x3 LazyVerticalGrid的小应用,想要修改网格元素颜色但始终无法实现。点击SHUFFLE按钮时,日志显示List内的颜色标识值已改变,且已使用val cols = remember { mutableStateOf(RRCols) },但UI仍未更新。
相关代码
MainActivity.kt
class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { RubiksRaceTheme { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background ) { Column( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Center, modifier = Modifier .fillMaxSize() .padding(top = 30.dp) ) { Image(painter = painterResource(id = R.drawable.rrlogo), contentDescription = "Logo", modifier = Modifier .fillMaxWidth() .padding(60.dp) .scale(2f) ) val cols = remember { mutableStateOf(RRCols) } RRGrid(cols) Button(onClick = { shuffle(cols) }, colors = ButtonDefaults.buttonColors( contentColor = Color(0xFFFFFFFF), backgroundColor = RRBlue ), modifier = Modifier .fillMaxWidth() .padding(horizontal = 8.dp, vertical = 50.dp) .background(RRInv) .size(100.dp) ) { Text(text = "SHUFFLE", fontSize = 36.sp ) } } } } } } } @Composable fun RRGrid (rrCols: MutableState<MutableList<String>>) { Box(contentAlignment = Alignment.Center, modifier = Modifier .fillMaxWidth() ) { LazyVerticalGrid(columns = GridCells.Fixed(3), contentPadding = PaddingValues(12.dp) ) { items(rrCols.value) { val col = RRColMap[it] ?: RRWhite Card(modifier = Modifier .padding(4.dp) .background(col) .size(110.dp) ) { Box(modifier = Modifier .background(col)) } } } } } fun shuffle(rrCols: MutableState<MutableList<String>>) { var check = mutableListOf<Int>(0,0,0,0,0,0) for (i in 0..8) { var num = Random.nextInt(0,6) while (check[num] >= 4) { num = Random.nextInt(0,6) } check[num] += 1 rrCols.value[i] = RRNumCol[num] ?: "w" } Log.v("SET", RRCols.toString()) }
data.kt
var RRCols = mutableListOf("w", "w", "w", "w", "w", "w", "w", "w", "w") val RRColMap = mapOf( "w" to RRWhite, "r" to RRRed, "b" to RRBlue, "g" to RRGreen, "o" to RROrange, "y" to RRYellow ) val RRNumCol = mapOf( 0 to "w", 1 to "r", 2 to "b", 3 to "g", 4 to "o", 5 to "y" )
解决方案
核心问题:Jetpack Compose的MutableState仅监听引用变化,修改MutableList内部元素不会改变集合引用,因此无法触发UI重组。需调整为每次更新时生成新的集合实例,触发State的引用变化。
修改步骤:
- 替换可变集合为不可变集合,避免直接修改原集合内部元素
- 每次shuffle生成新List,并赋值给State以触发重组
- 调整参数类型,符合Compose单向数据流原则
修改后的代码:
调整data.kt中的RRCols为不可变List
val RRCols = listOf("w", "w", "w", "w", "w", "w", "w", "w", "w")
修改MainActivity中的remember初始化
val cols = remember { mutableStateOf(RRCols) }
更新shuffle函数
fun shuffle(rrCols: MutableState<List<String>>) { val check = mutableListOf(0, 0, 0, 0, 0, 0) val newCols = mutableListOf<String>() for (i in 0..8) { var num = Random.nextInt(0, 6) while (check[num] >= 4) { num = Random.nextInt(0, 6) } check[num] += 1 newCols.add(RRNumCol[num] ?: "w") } rrCols.value = newCols Log.v("SET", rrCols.value.toString()) }
修改RRGrid的参数类型
@Composable fun RRGrid(rrCols: State<List<String>>) { // 内部实现保持不变 }
原理说明
- 使用不可变
List后,每次shuffle都会生成新的集合实例,赋值给State时会改变引用,触发Compose的重组机制,更新UI - 采用
State<List<String>>替代MutableState<MutableList<String>>,符合Compose单向数据流设计,减少意外的可变副作用
内容的提问来源于stack exchange,提问作者Ian
相关产品推荐
相关产品推荐

