Compose 什么叫重组?怎么样触发重组?

重组(Recomposition) 是 Jetpack Compose 的核心机制:当 Composable 读取的状态发生变化时,Compose 会重新执行读取了该状态的那部分 Composable 函数,用新的状态重新生成 UI 描述,然后更新界面。

它不是重新创建 Activity/View,也不是整棵树全部重建,而是按需、可跳过地重新执行相关 @Composable 代码。


一、什么叫重组?

Compose 是声明式 UI:

kotlin

复制代码
UI = f(state)

当 state 变了,Compose 需要重新调用 f 来得到新的 UI。这个"重新调用受影响的 Composable"的过程就叫重组。

例如:

kotlin

复制代码
@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Column {
        Text("Count = $count") // 读取了 count
        Button(onClick = { count++ }) { // 写入 count
            Text("+1")
        }
    }
}

点击按钮时:

  1. count++ 修改了 MutableState。

  2. Compose 发现 Text("Count = $count") 读取过 count。

  3. 于是标记相关重组作用域为无效。

  4. 下一帧重新执行相关 Composable。

  5. Text 显示新的数字。


二、重组的特点

  • 按需触发:只重组读取了变化状态的作用域。

  • 可以跳过 :如果参数是稳定类型且 equals 相等,Compose 可能跳过子 Composable。

  • 可能频繁发生:Composable 应尽量幂等、快速、无副作用。

  • 不是重新创建 View:Compose 会 diff 新旧节点树,只更新需要更新的部分。


三、怎样触发重组?

核心一句话:

被 Composable 读取的 State 发生变化,就会触发重组。

常见触发方式:

1. 修改 MutableState

kotlin

复制代码
var count by remember { mutableStateOf(0) }
count++ // 触发

底层是:

kotlin

复制代码
val count = remember { mutableStateOf(0) }
count.value++ // 触发

2. 修改 Snapshot 集合

kotlin

复制代码
val list = remember { mutableStateListOf<Int>() }
list.add(1) // 触发读取该 list 的 Composable 重组

类似还有:

kotlin

复制代码
mutableStateMapOf()

3. StateFlow / LiveData 转成 State

kotlin

复制代码
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

当 StateFlow 发射新值时,collectAsStateWithLifecycle() 会更新对应的 State,从而触发重组。

LiveData 类似:

kotlin

复制代码
val data by liveData.observeAsState()

4. 父 Composable 重组,导致子 Composable 参数变化

父级重组时,会重新调用子 Composable。

如果子 Composable 的参数发生变化,或者参数类型不稳定,子 Composable 可能重组。

如果参数是稳定类型且 equals 相等,Compose 可以跳过子 Composable。

5. CompositionLocal 变化

kotlin

复制代码
CompositionLocalProvider(LocalColor provides newColor) {
    // 读取 LocalColor.current 的 Composable 会重组
}

6. remember(key) 的 key 变化

kotlin

复制代码
remember(key) { ... }

当 key 变化时,remember 会重新计算。

但 key 变化通常也是因为某个 State 变化导致当前 Composable 重组。


四、什么不会触发重组?

  • 修改普通变量:

kotlin

复制代码
var count = 0
count++ // 不会触发 UI 更新
  • 修改普通集合:

kotlin

复制代码
val list = mutableListOf<Int>()
list.add(1) // 不会触发
  • 修改了一个 State,但没有任何 Composable 读取它:

kotlin

复制代码
val state = mutableStateOf(0)
state.value = 1 // 如果没人读取,不会触发 UI 重组

五、总结

  • 重组:状态变化后,Compose 重新执行读取了该状态的 Composable,以更新 UI。

  • 触发条件 :被 Composable 读取的 State 发生变化。

  • 常见来源 :mutableStateOf、mutableStateListOf、collectAsState、CompositionLocal、父级重组导致参数变化等。

  • 注意 :Composable 可能被多次执行,不要在 Composable 函数体里直接做网络请求、修改外部变量等副作用;应使用 LaunchedEffect、SideEffect、DisposableEffect 等。

相关推荐
硫酸锌011 小时前
安卓手机连接Windows电脑后通过DHCP服务为手机分配IP地址
android·windows·计算机网络
骑着蜗牛撵大象3271 小时前
设备监控数据存与查:Spring Boot 接入 TimescaleDB 超表的完整落地
android·spring boot·后端·springboot·时序数据库·es·设备监控
云贝贝贝1 小时前
MySQL 线上报 Lock wait timeout 别慌:6 招定位锁等待与死锁
android
mmsx2 小时前
Android 签名校验为什么能拦住二次打包:指纹与完整性校验
android·签名
jason.zeng@15022072 小时前
使用vscode+flutter开发android程序(入门)
android·vscode·flutter
事圆则缓2 小时前
Kotlin学习导航:从知识树走到项目与面试
android·开发语言·kotlin
天空之城--3 小时前
近一周Android开发动态:AI编码、Compose与自适应实践
android
mmsx3 小时前
Android 混淆挡不住二次打包:一条完整的攻击链与突破口
android·混淆