在 Jetpack Compose 中,我们经常听到“重组(Recomposition)”这个词。那么,什么是重组?它的作用域到底有多大?如何避免不必要的重组?
今天我们就围绕一个关键结论来展开讲解:
@Composable 函数就是重组的最小作用域。
✨ 示例:问题出现在哪里?
来看下面这段代码:
@Composable
fun Demo() {var count by remember { mutableIntStateOf(0) }Column(modifier = Modifier.randomColorBg()) {Text(modifier = Modifier.randomColorBg(),text = "count = $count")Button(modifier = Modifier.randomColorBg(),onClick = { count++ }) {Text(modifier = Modifier.randomColorBg(),text = "Increase")}}
}
每次点击按钮,count
会更新。由于 count
是 Demo()
函数的状态依赖,整个 Demo 函数会重新执行,包括其中的 Text
和 Button
都会被重新组合。
如果 randomColorBg()
每次调用都会返回一个新颜色,那么每次点击都会让背景色发生变化,即使文字内容没变,这显然是不必要的重组。
✅ 优化:拆分作用域
我们将组件拆成多个函数,让 count
只影响 CountText
:
@Composable
fun Demo() {var count by remember { mutableIntStateOf(0) }Column(modifier = Modifier.randomColorBg()) {CountText(count)IncreaseButton { count++ }}DemoText()
}@Composable
fun CountText(count: Int) {Text(modifier = Modifier.randomColorBg(),text = "count = $count")
}@Composable
fun IncreaseButton(onClick: () -> Unit) {Button(modifier = Modifier.randomColorBg(),onClick = onClick) {Text(modifier = Modifier.randomColorBg(),text = "Increase")}
}@Composable
fun DemoText() {Text(modifier = Modifier.randomColorBg(),text = "Demo")
}
现在,只有 CountText 会因为 count 改变而重组,其他组件保持不变!
🎨 重组作用域示意图
graph TDA[Demo()] --> B[CountText(count)]A --> C[IncreaseButton(onClick)]A --> D[DemoText()]subgraph count 变化后重组Bendsubgraph 未变化时保持不变CDend
这个图告诉我们:只有 count 发生变化时依赖它的 CountText 会被重组,其它保持稳定。
💡 小结
@Composable
函数是重组的作用域。- 如果函数参数或依赖的 State 改变了,该函数会被重新执行。
- 函数内部的所有代码会随之重新构建。
- 拆分函数、减少不必要的依赖,是优化 Compose 性能的关键。
☑️ 实战建议
- 拆分 UI 组件,保持每个函数的职责单一。
- 避免在 Composable 外部使用不稳定的值(如
randomColorBg()
),应只在必要组件中调用。 - 使用
remember
、derivedStateOf
缓存中间状态,减少重组。