Jetpack Compose中remember值showTask重组被遗忘问题咨询
Jetpack Compose 重组状态问题解答
参考示例Composable代码如下:
@Composable fun WaterCounter( modifier: Modifier = Modifier, ) { var count by remember { mutableStateOf(0) } Column( modifier = modifier.padding(16.dp) ) { if (count > 0) { var showTask by remember { mutableStateOf(true) } if (showTask) { WellnessTaskItem( taskName = "Have you taken your 15 minute walk today?", onClose = { showTask = false }) } Text( text = "You've had $count glasses", modifier = modifier.padding(16.dp) ) } Row( modifier = modifier.padding(top = 8.dp) ) { Button( onClick = { count++ }, enabled = count < 10, ) { Text(text = "add one") } Button( onClick = { count = 0 }, modifier = modifier.padding(start = 8.dp) ) { Text(text = "Clear water count") } } } }
问题1:为什么showTask会被遗忘?
核心原因是Compose中remember存储的状态,是和调用remember的代码在执行流程中的位置强绑定的,不会脱离代码执行逻辑永久留存。
观察代码可以发现,声明showTask的remember语句写在if (count > 0)的条件分支内部。当点击Clear按钮把count重置为0触发重组时,count > 0的判断结果为false,整个if分支内的代码都不会被执行,自然也不会跑到声明showTask的那行代码。Compose检测到之前绑定在这个代码位置的状态,在本次重组中没有对应的代码调用,就会直接销毁这个位置存储的showTask状态值。等下次count重新大于0、再次执行到这行remember时,会重新走初始化逻辑把showTask设为默认值true,之前用户关闭任务项把showTask改成false的状态会完全丢失,也就是教程里说的“被遗忘”。
问题2:“代码未被调用”“离开Composition”分别是什么含义?
- 代码未被调用:Compose的重组过程本质是按你写的代码顺序从上到下执行Composable函数的过程,遇到
if、when这类条件分支时,会根据当前的状态值判断要执行哪一段分支逻辑。当count=0时,if (count > 0)的条件不成立,Kotlin会直接跳过整个if块包裹的所有代码,块内声明showTask、判断是否渲染WellnessTaskItem、渲染显示喝水杯数的Text这些代码行,在本次重组中完全不会被执行,这就是“代码未被调用”。 - 离开Composition:Composition可以理解为Compose框架维护的、当前屏幕上实际生效渲染的所有UI节点构成的树结构。之前count>0的时候,if块内的
Text、WellnessTaskItem组件执行时,会被注册到这棵Composition树上,拥有自己的位置、状态和渲染逻辑。当重组时这些组件对应的代码完全没被执行,Compose就会判定这些节点不再需要被展示,直接把它们从Composition树中移除,对应的组件实例、绑定的临时状态都会被销毁,屏幕上也不再显示这些内容,这个移除的过程就是“离开Composition”。
内容的提问来源于stack exchange,提问作者Helios
相关产品推荐
相关产品推荐

