https://developer.android.google.cn/develop/ui/compose/mental-model?hl=zh-cn
目录
一、基本思想
💡 核心思想:声明性UI
在传统的命令式UI中,你需要手动获取视图对象并调用其方法(如setText())来更新界面。这不仅繁琐,还容易导致状态不一致。
Compose采用的是声明性范式。你只需要描述界面应该呈现的样子,它完全由状态驱动。
- UI = f(状态):界面是状态的一个函数。当状态变化时,Compose会智能地重新执行受影响的可组合函数,并自动更新界面。这个过程被称为重组。
🧱 基本构建单元:可组合函数
可组合函数是Compose中最基础的单元,它有以下几个重要特征:
@Composable注解:所有可组合函数都必须有此注解,以告知编译器将其转换为界面。- 接受数据,发出UI:函数接收数据作为参数,并通过调用其他可组合函数来生成界面。
- 无返回值:它不返回任何对象,而是描述了目标屏幕的状态。
- 快速、幂等、无副作用:这是可组合函数为了支持高效重组而必须遵循的重要属性。后面会详细解释。
🔄 动态内容与Kotlin的力量
因为可组合函数是用Kotlin编写的,所以它拥有了底层语言的全部灵活性。
- 你可以使用
if语句来决定是否显示某个元素。 - 你可以使用
for循环来动态生成列表。 - 你可以定义变量、调用辅助函数等。
这种灵活性是Compose的强大优势之一,让你可以更简洁、自然地构建动态界面。
⚙️ 核心机制:智能重组
重组是Compose响应状态变化、更新界面的核心机制。为了提高效率,Compose采用了一系列优化策略,理解这些对你写出正确、高效的代码至关重要。
- 跳过不必要的重组:Compose会尽力只重组那些输入参数已更改的部分。例如,在列表中,如果
header变了而names没变,LazyColumn的列表项就可能被跳过,不会重组。 - 乐观地取消和重启:重组是乐观操作,如果在新重组完成前参数又变了,Compose会取消当前重组并用新参数重新开始。
- 高频执行:可组合函数可能非常频繁地运行(例如动画的每一帧)。因此,函数内部绝不能执行耗时操作(如读取文件),否则会导致界面卡顿。
- 可能并行运行:为了优化性能,Compose可以在后台线程池中并行执行不同的可组合函数。
- 执行顺序不确定:同一层级下的可组合函数调用(如
StartScreen()和EndScreen()),其执行顺序是不保证的。它们不应相互依赖。
⚠️ 最重要的规则:无副作用
上述所有优化策略(跳过、取消、并行、顺序不定)共同指向了Compose编程中最重要的一条规则:可组合函数必须保持“无副作用”。
所谓副作用,是指对可组合函数作用域外部的可见状态所做的任何更改。例如:
- 写入共享对象的属性或全局变量。
- 更新
ViewModel中的可观察项。 - 写入
SharedPreferences或数据库。
违反这条规则会导致难以预测的bug,比如界面显示错误的状态,或是在重组被取消后依然错误地应用了某些操作。
✅ 最佳实践与模式
为了遵循上述规则,你需要采用新的编程模式:
-
将数据作为参数传入:不要从可组合函数内部读取
SharedPreferences或资源,而是将读取后的值作为参数传递进来。 -
通过回调触发操作:当用户交互需要改变状态时(如点击按钮),通过回调函数(如
onClick)将事件传递给ViewModel或其他逻辑层去处理状态更新。kotlin
// 正确做法:无副作用,仅依赖输入和回调 @Composable fun SharedPrefsToggle( value: Boolean, // 状态作为参数传入 onValueChanged: (Boolean) -> Unit // 操作通过回调传出 ) { Checkbox(checked = value, onCheckedChange = onValueChanged) }
📌 总结要点
| 核心概念 | 简要说明 |
|---|---|
| 声明性UI | UI是状态的函数,UI = f(状态)。 |
| 可组合函数 | 用@Composable标记,描述UI,无返回值。 |
| 智能重组 | 状态变化时,高效、智能地更新UI的机制。 |
| 无副作用 | 最重要的规则:不修改外部状态,不执行耗时操作。 |
| 状态提升 | 将状态移至可组合项外部,通过参数和回调传递。 |
二、@Compose注解
一句话理解
@Composable 就是告诉 Compose:"这个函数需要被追踪,当它依赖的数据变化时,重新执行它"。
3个核心点
1. 它不是普通函数
kotlin
// 普通函数:执行一次就完事
fun sayHello() = println("Hello")
// Composable:可以被反复执行(重组)
@Composable
fun SayHello() {
println("Hello") // 当依赖的状态变化时,会再次执行
}
2. 它必须被 @Composable 函数调用
kotlin
// ❌ 错误
fun normalFunction() {
SayHello() // 编译错误!
}
// ✅ 正确
@Composable
fun composableFunction() {
SayHello() // 可以调用
}
3. 它可以自动响应数据变化
kotlin
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
// 当 count 变化时,这个 Text 会自动更新
Text("计数: $count")
Button(onClick = { count++ }) {
Text("增加")
}
}
记忆口诀
"@Composable 是响应式的标记,让函数可以反复执行并自动更新"
对比理解
| 普通函数 | @Composable 函数 |
|---|---|
| 执行一次 | 可以执行多次(重组) |
| 不追踪数据 | 追踪数据变化 |
| 哪里都能调 | 只能在 @Composable 中调 |
| 自己控制更新 | Compose 自动控制更新 |
90% 的场景你只需要知道:
- 用
@Composable标记你的 UI 函数 - 在里面可以使用
remember、mutableStateOf - 数据变了 UI 自动更新
0 条评论