目录
一、状态管理知识框架
📚 状态管理核心知识点
| 知识点 | 核心内容 | 关键API/概念 |
|---|---|---|
| 状态与组合 | Compose是声明式UI,更新UI的唯一方式是使用新参数调用可组合项。状态变化触发重组。 | 重组、可组合函数 |
| 可组合项中的状态 | 使用remember在重组后保持状态。mutableStateOf创建可观察的MutableState,其value变化会触发读取它的重组。 |
remember { mutableStateOf(...) }、by委托、rememberSaveable(处理配置变更) |
| 其他状态类型支持 | 将其他可观察类型(如Flow、LiveData)转换为State,以便在Compose中使用。 |
collectAsStateWithLifecycle()(推荐用于Android)、collectAsState、observeAsState() |
| 有状态 vs 无状态 | 有状态:内部保持状态(方便但不灵活)。无状态:不保持任何状态(更可复用、易测试)。 | 设计可组合项时,优先考虑无状态。 |
| 状态提升 | 将状态移至调用方,使可组合项无状态的模式。通常替换为value和onValueChange两个参数。 |
单向数据流:状态向下流动,事件向上流动。 |
| 状态恢复 | 在配置变更或进程重建后保留状态。rememberSaveable通过Bundle自动保存支持的类型,或通过Saver(如mapSaver、listSaver)保存自定义对象。 |
rememberSaveable、@Parcelize、MapSaver、ListSaver |
| 带键的remember | remember接受key参数,当key变化时,缓存失效并重新计算。用于控制成本高昂对象的生命周期。 |
remember(key1 = someValue) { ... } |
| 状态容器 | 当状态逻辑变复杂时,应将逻辑和状态事务委派给专门的状态容器类,而不是写在可组合函数中。 | 状态容器、ViewModel通常是状态容器的实现。 |
💡 核心思维导图
文档中的状态管理思想可以概括为以下流程:
- 定义可观察状态:使用
mutableStateOf创建。 - 在组合中保持:使用
remember或rememberSaveable包裹。 - 通过UI展示:在可组合项中读取
State.value,系统自动订阅。 - 通过事件更新:UI触发事件(如
onValueChange),更新状态值。 - 触发重组:状态值改变,Compose 重新执行读取该状态的代码块。
- 提升关键状态:将需要共享或控制的“状态”和“事件”提升到父级,实现无状态、可复用的组件。
二、Compose 状态管理 API 完全总结
一、核心状态创建 API
1. mutableStateOf 系列
kotlin
// 基本类型
val state = mutableStateOf(0) // State<Int>
val state = mutableStateOf("") // State<String>
val state = mutableStateOf(false) // State<Boolean>
// 专用类型(避免装箱,性能更好)
val state = mutableIntStateOf(0) // MutableIntState
val state = mutableLongStateOf(0L) // MutableLongState
val state = mutableFloatStateOf(0f) // MutableFloatState
val state = mutableDoubleStateOf(0.0) // MutableDoubleState
val state = mutableBooleanStateOf(false) // MutableBooleanState
// 集合类型
val list = mutableStateListOf<String>() // SnapshotStateList<String>
val map = mutableStateMapOf<String, Int>() // SnapshotStateMap<String, Int>
2. mutableStateOf 的几种使用方式
kotlin
// 方式1:直接访问 .value
val countState = remember { mutableStateOf(0) }
Text("计数: ${countState.value}")
Button(onClick = { countState.value++ })
// 方式2:by 委托(最常用)
var count by remember { mutableStateOf(0) }
Text("计数: $count")
Button(onClick = { count++ })
二、状态保持 API
1. remember - 重组后保持
kotlin
// 基本用法
var count by remember { mutableStateOf(0) }
// 带 key 的 remember(key 变化时重新计算)
val expensiveObject = remember(key1 = userId, key2 = filter) {
ExpensiveObject(userId, filter) // userId 或 filter 变化时重新创建
}
// 记住计算结果
val filteredList = remember(list, filter) {
list.filter { it.contains(filter) } // list 或 filter 变化时重新计算
}
2. rememberSaveable - 配置变更后保持
kotlin
// 基本类型自动保存
var text by rememberSaveable { mutableStateOf("") }
var count by rememberSaveable { mutableIntStateOf(0) }
// 自定义对象需要 Saver
@Parcelize
data class User(val name: String, val age: Int) : Parcelable
var user by rememberSaveable { mutableStateOf(User("", 0)) }
// 使用自定义 Saver
var tasks by rememberSaveable(stateSaver = TaskListSaver) {
mutableStateOf(emptyList<Task>())
}
三、状态派生 API
1. derivedStateOf - 派生状态
kotlin
var count by remember { mutableStateOf(0) }
// 基础派生
val isEven by remember {
derivedStateOf { count % 2 == 0 }
}
// 复杂派生
val stats by remember {
derivedStateOf {
Stats(
total = items.size,
completed = items.count { it.completed },
active = items.count { !it.completed }
)
}
}
// 防抖/节流效果
val debouncedQuery by remember {
derivedStateOf {
// 只有查询稳定 300ms 后才更新
query.takeIf { it.isNotBlank() }
}
}
四、状态收集 API(与其他框架集成)
1. Flow 集成
kotlin
// 生命周期感知的 Flow 收集(推荐 Android 使用)
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
// 普通 Flow 收集
val data by flow.collectAsState(initial = null)
// StateFlow 转换
val state by stateFlow.collectAsState()
2. LiveData 集成
kotlin
// 需要添加依赖:runtime-livedata
val liveData = MutableLiveData(0)
val count by liveData.observeAsState(initial = 0)
3. RxJava 集成
kotlin
// 需要添加相应依赖
val observable = Observable.just(1)
val value by observable.subscribeAsState(initial = 0)
五、集合状态 API
1. mutableStateListOf
kotlin
val items = remember { mutableStateListOf<String>() }
// 支持所有 List 操作
items.add("新项目")
items.removeAt(0)
items[0] = "更新"
items.clear()
// 触发重组的方法
items.addAll(listOf("a", "b"))
items.removeAll { it.startsWith("a") }
items.retainAll { it.length > 3 }
2. mutableStateMapOf
kotlin
val map = remember { mutableStateMapOf<String, Int>() }
// 支持所有 Map 操作
map["key"] = 1
map.put("another", 2)
map.remove("key")
map.clear()
六、比较表格
| API | 作用范围 | 生命周期 | 使用场景 | 示例 |
|---|---|---|---|---|
mutableStateOf |
单个值 | 跟随 remember | 基本状态 | var text by remember { mutableStateOf("") } |
mutableIntStateOf |
Int 值 | 跟随 remember | Int 状态(性能优化) | var count by remember { mutableIntStateOf(0) } |
mutableStateListOf |
列表 | 跟随 remember | 可变列表 | val list = remember { mutableStateListOf<String>() } |
mutableStateMapOf |
映射 | 跟随 remember | 可变 Map | val map = remember { mutableStateMapOf<String, Int>() } |
remember |
任何对象 | 重组后 | 保持对象 | val obj = remember { ExpensiveObject() } |
rememberSaveable |
任何对象 | 配置变更后 | 恢复状态 | var text by rememberSaveable { mutableStateOf("") } |
derivedStateOf |
派生值 | 依赖变化时 | 计算属性 | val isValid by remember { derivedStateOf { text.length > 3 } } |
collectAsState |
Flow | 收集期间 | Flow 转 State | val data by flow.collectAsState() |
七、选择指南
如何选择正确的 API:
- 是否需要跨重组保持?
- 是 →
remember - 否 → 普通变量(不推荐)或参数
- 是 →
- 是否需要跨配置变更保持?
- 是 →
rememberSaveable - 否 →
remember
- 是 →
- 状态类型是什么?
- 基本类型 →
mutableStateOf或专用类型 - 列表 →
mutableStateListOf - Map →
mutableStateMapOf - 复杂对象 →
mutableStateOf+Saver
- 基本类型 →
- 是否依赖其他状态?
- 是 →
derivedStateOf - 否 → 直接使用
- 是 →
- 数据来源?
- ViewModel/Flow →
collectAsStateWithLifecycle - LiveData →
observeAsState - 本地状态 →
mutableStateOf
- ViewModel/Flow →
八、最佳实践总结
kotlin
@Composable
fun BestPracticesDemo() {
// ✅ 好:使用专用类型避免装箱
var count by remember { mutableIntStateOf(0) }
// ✅ 好:需要跨配置变更使用 rememberSaveable
var text by rememberSaveable { mutableStateOf("") }
// ✅ 好:复杂计算使用 derivedStateOf
val processedData by remember(data) {
derivedStateOf { expensiveOperation(data) }
}
// ✅ 好:列表使用 mutableStateListOf
val items = remember { mutableStateListOf<String>() }
// ✅ 好:使用 key 控制生命周期
val filtered = remember(key1 = filter) {
items.filter { it.contains(filter) }
}
// ✅ 好:ViewModel 数据用生命周期感知收集
val viewState by viewModel.state.collectAsStateWithLifecycle()
}
这个总结涵盖了 Compose 中所有主要的状态管理 API 及其使用场景。核心原则是:选择最适合你需求的 API,保持状态生命周期清晰,优化性能。
三、mutableStateOf 类型 vs 基本数据类型
一、本质区别
kotlin
// 普通 Int 变量
var count = 0 // 只是普通的值
// MutableState<Int> 对象
val countState = mutableStateOf(0) // 是一个包装对象
二、内存结构对比
普通数据类型
kotlin
var count = 0
- 直接在栈上存储值(基本类型)或堆上存储引用(对象)
- 不包含任何附加信息
- Compose 无法追踪它的变化
MutableState 类型
kotlin
val countState = mutableStateOf(0)
在堆上创建的对象结构:
text
MutableState 对象 {
value: 0, // 实际存储的值
listeners: [], // 监听器列表(哪些可组合项在读取)
snapshotId: 123, // 快照ID
policy: equalityPolicy // 比较策略
}
三、详细对比表格
| 特性 | 普通数据类型 | MutableState<T> |
|---|---|---|
| 本质 | 纯粹的值 | 带有追踪能力的容器对象 |
| 存储位置 | 栈(基本类型)或堆 | 堆(总是对象) |
| 内存占用 | 小 | 较大(有额外开销) |
| 可观察性 | ❌ 不可观察 | ✅ 可观察变化 |
| 触发重组 | ❌ 不能 | ✅ 能触发重组 |
| 线程安全 | 不保证 | ✅ 快照系统保证 |
| 比较策略 | 无 | 可配置相等性比较 |
| 序列化 | 直接 | 需要额外处理 |
四、代码对比示例
1. 更新方式
kotlin
@Composable
fun Comparison() {
// 普通变量 - 不会触发重组
var normalCount = 0
Button(onClick = { normalCount++ }) { // UI 不会更新!
Text("普通: $normalCount") // 永远显示 0
}
// State 变量 - 触发重组
var stateCount by remember { mutableStateOf(0) }
Button(onClick = { stateCount++ }) { // UI 会更新
Text("State: $stateCount")
}
}
五、总结:关键区别
| 方面 | 普通数据类型 | MutableState |
|---|---|---|
| 追踪能力 | 无 | 有(记录读取者) |
| 响应式 | 不支持 | 支持(值变化通知) |
| 内存开销 | 小 | 较大(对象头+监听器) |
| 访问速度 | 快 | 稍慢(有委托开销) |
| 线程安全 | 不保证 | 有快照机制保证 |
| 适用场景 | 一次性值、内部计算 | 需要触发UI更新的值 |
核心要点
MutableState是一个容器:它包装了实际值,并添加了追踪能力- Compose 需要这个容器:才能知道什么时候需要重组
- 性能权衡:用少量内存和计算开销换取响应式更新
- 只在必要时使用:只有影响UI的状态才需要包装成
MutableState
简单来说:普通数据类型是值本身,MutableState 是带有监听能力的值容器。你需要UI响应式更新时用 MutableState,否则用普通变量。
0 条评论