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 等。

相关推荐
传奇开心果5 小时前
【Flutter踩坑排雷】第5课:扩展方法冲突坑|同名扩展引发编译歧义,故障规避手段
android·flutter
.痞老板.8 小时前
mysql初阶--数据类型
android·数据库·mysql
StarsGreen8 小时前
Android 启动流程详解
android·linux·单片机·嵌入式硬件
booboosui1 天前
Android 上来电怎么判:7 个条件加 5 个中文词
android
MardaWang1 天前
App 内嵌 H5 的信任边界设计(ArkWeb/HarmonyOS 实战)
android
石头慢慢说1 天前
不写 XPath,让 AI 在真机上跑测试:Appium MCP 全流程实战
android
90后的晨仔1 天前
解决 Android 构建报错:Unable to delete file .../file-map.txt
android·前端
mg6681 天前
安卓玩机工具----安卓手机变成桌面电脑!多窗口镜像+音频投射+游戏操控,无需 Root
android·智能手机·电脑
peakmain91 天前
异常处理 - Native 层的崩溃捕获机制及实现 (一)
android·性能优化
木头左1 天前
【Android】听写播放器改版:中英文书写速度拆项与「正在读」高亮
android·room·media3·jetpack compose·听写