先把结论放在前面:Compose 的重组能跳过,靠的是\”参数稳定性判定 + 编译器插入的依赖追踪\”两件事。 编译器在编译期给每个 Composable 算出\”读了哪些状态\”的依赖集合,运行时状态变化时只把依赖它的重组作用域放进待执行队列;而\”能否跳过整个 Composable\”则由参数是否\”稳定\”决定——稳定参数在两次调用间用 equals 比较,相同就直接返回,连函数体都不执行。
这道题的答案确实藏在演进过程里:早期 Compose 依赖一个\”Positional Memoization\”方案(按调用位置记缓存),位置一变缓存就失效;后来改成\”按调用点分组 + 编译器生成 group key\”,才有了今天\”位置无关\”的跳过能力。能讲出这段演进,说明理解的是设计动机而不是背下来的规则。
为什么能跳过:两套机制
机制一:依赖追踪(决定\”谁要重组\”)。
@Composable
fun Counter(count: Int, onClick: () -> Unit) {
val doubled = count * 2 // 依赖 count
val label = remember(count) { \”值:$count\” } // 依赖 count,且有缓存
Text(text = label, modifier = Modifier.clickable(onClick = onClick))
}
编译后 Counter

