了解 Jetpack Compose 中的重组
Jetpack Compose通过使 Android UI 具有声明性和响应性,彻底改变了我们构建 Android UI 的方式。 Compose 中最重要的概念之一是重组。这个概念对于理解 UI 元素如何有效更新以响应状态变化至关重要。在本文中,将探讨什么是重组、它在 Jetpack Compose 中的工作原理,并提供示例来演示其行为。
什么是重组?
在 Jetpack Compose 中,UI 是使用称为composables
的函数构建的。这些函数将数据作为输入并根据该数据发出 UI 元素。当可组合项的输入数据(或状态)发生更改时,Compose 会自动重新计算(或“重新组合”)可组合项以反映新状态。这个过程称为重组(recomposition)。
每当可组合函数读取的状态发生变化时,都会发生重组。 Jetpack Compose 无需重新绘制整个 UI,而是仅高效地重新执行那些需要更新的可组合项,从而提高性能。
重组的要点
• 重组是由状态变化触发的。
• Compose 尝试通过仅重新执行受更改影响的 UI 部分来优化重组过程。
• 如果输入数据未更改,则不会发生这种情况。
• 重组是声明性的:您根据状态描述所需的 UI,Compose 在状态更改时更新它。
示例:了解State重组
通过一个示例来说明 Jetpack Compose 中的重组。
@Composable
fun Counter() {
// 'count' is the state that controls recomposition
var count by remember { mutableStateOf(0) }
// The Text and Button composables will be recomposed every time 'count' changes
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
// Display the current count
Text(text = "Count: $count", fontSize = 24.sp)
// Button that increments the count on click
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
解释:
- mutableStateOf(0) :我们使用mutableStateOf创建状态变量count 。这是 Compose 中的一种特殊类型的状态,当状态发生变化时可以触发重组。
- Text和Button :这些是依赖于count状态的可组合项。 Text可组合项将显示count的值,而Button允许用户增加它。
- 重新组合:每次单击按钮并且count增加时,可组合项都会重新组合,更新 UI 以反映新的计数。
示例:最小化不必要的重组
有时,如果 UI 的某些部分所依赖的状态未更改,如果要避免重新组合。 Compose 通过确保仅重组相关部分来优化重组。
@Composable
fun CounterWithStaticText() {
var count by remember { mutableStateOf(0) }
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
// This part will not recompose, as it does not depend on 'count'
StaticText()
// This part will recompose when 'count' changes
Text(text = "Count: $count", fontSize = 24.sp)
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
@Composable
fun StaticText() {
Text("This text does not change.", fontSize = 18.sp)
}
解释:
StaticText
可组合项不依赖于任何状态,因此当count更改时它不会被重新组合。只有显示计数的Text和按钮才会重新组合。
这演示了如何在发生不相关的状态更改时防止 UI 的静态部分进行不必要的重组。
使用remember
和rememberSaveable
Compose 中的remember函数用于存储在重组后仍能保存的值。如果没有它,每次重构函数时都会重置状态。
@Composable
fun RememberCounter() {
// 'remember' ensures that 'count' survives recompositions
var count by remember { mutableStateOf(0) }
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text(text = "Remembered Count: $count", fontSize = 24.sp)
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
使用remember , count在重组之间保留其值。这对于存储与 UI 相关的状态非常有用,并且不应每次都重置。
如果想在配置更改时保存状态(例如屏幕旋转),可以使用rememberSaveable
:
@Composable
fun SaveableCounter() {
// 'rememberSaveable' saves state across configuration changes
var count by rememberSaveable { mutableStateOf(0) }
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier.fillMaxSize()
) {
Text(text = "Saveable Count: $count", fontSize = 24.sp)
Button(onClick = { count++ }) {
Text("Increment")
}
}
}
示例:使用 Kotlin 协程流进行重组
Kotlin 的Flow通常用于观察数据的变化,可以将其与 Compose 结合起来进行响应式 UI 更新。下面是一个示例,其中使用Flow发出在 Compose 中触发重组的值。
@Composable
fun CounterWithFlow() {
// Create a Flow that emits incremented values every second
val counterFlow = flow {
var counter = 0
while (true) {
delay(1000L)
emit(counter++)
}
}
// Collect the flow and use it to display the counter
val counter by counterFlow.collectAsState(initial = 0)
Text(text = "Counter: $counter", fontSize = 24.sp)
}
解释:
• 定义一个每秒发出一个新计数器值的Flow 。
• collectAsState()收集Flow并在每次发出新值时触发重组。
• UI 会自动更新以显示计数器的最新值,无需显式 UI 更新。
重组什么时候发生?
- 当可组合函数中使用的状态发生变化时(例如,当更新mutableStateOf时)。
- 当Flow 、 LiveData或StateFlow中的状态发生更改并收集在可组合项中时。
- 当父可组合项被重组时,其子项也可能会重组,具体取决于它们是否依赖于已更改的状态。
结论
Jetpack Compose 中的重组是一个强大的概念,可确保您的 UI 对状态更改保持反应。它使 UI 变得动态并消除了手动更新的需要。通过使用remember
、rememberSaveable
和 Kotlin Coroutines Flow等工具,可以有效地管理重组并创建响应灵敏且流畅的 UI。
使用 Jetpack Compose 构建更复杂的应用程序时,了解重组对于优化性能和确保流畅的用户体验至关重要。 Compose 的声明性性质能编写更简单、更直观的 UI 代码