一、状态管理知识框架

📚 状态管理核心知识点

知识点 核心内容 关键API/概念
状态与组合 Compose是声明式UI,更新UI的唯一方式是使用新参数调用可组合项。状态变化触发重组 重组可组合函数
可组合项中的状态 使用remember重组后保持状态。mutableStateOf创建可观察的MutableState,其value变化会触发读取它的重组。 remember { mutableStateOf(...) }by委托、rememberSaveable(处理配置变更)
其他状态类型支持 将其他可观察类型(如FlowLiveData)转换为State,以便在Compose中使用。 collectAsStateWithLifecycle()(推荐用于Android)、collectAsStateobserveAsState()
有状态 vs 无状态 有状态:内部保持状态(方便但不灵活)。无状态:不保持任何状态(更可复用、易测试)。 设计可组合项时,优先考虑无状态。
状态提升 将状态移至调用方,使可组合项无状态的模式。通常替换为valueonValueChange两个参数。 单向数据流:状态向下流动,事件向上流动。
状态恢复 在配置变更或进程重建后保留状态。rememberSaveable通过Bundle自动保存支持的类型,或通过Saver(如mapSaverlistSaver)保存自定义对象。 rememberSaveable@ParcelizeMapSaverListSaver
带键的remember remember接受key参数,当key变化时,缓存失效并重新计算。用于控制成本高昂对象的生命周期。 remember(key1 = someValue) { ... }
状态容器 当状态逻辑变复杂时,应将逻辑和状态事务委派给专门的状态容器类,而不是写在可组合函数中。 状态容器、ViewModel通常是状态容器的实现。

💡 核心思维导图

文档中的状态管理思想可以概括为以下流程:

  1. 定义可观察状态:使用 mutableStateOf 创建。
  2. 在组合中保持:使用 rememberrememberSaveable 包裹。
  3. 通过UI展示:在可组合项中读取 State.value,系统自动订阅。
  4. 通过事件更新:UI触发事件(如 onValueChange),更新状态值。
  5. 触发重组:状态值改变,Compose 重新执行读取该状态的代码块。
  6. 提升关键状态:将需要共享或控制的“状态”和“事件”提升到父级,实现无状态、可复用的组件。

二、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:

  1. 是否需要跨重组保持?
    • 是 → remember
    • 否 → 普通变量(不推荐)或参数
  2. 是否需要跨配置变更保持?
    • 是 → rememberSaveable
    • 否 → remember
  3. 状态类型是什么?
    • 基本类型 → mutableStateOf 或专用类型
    • 列表 → mutableStateListOf
    • Map → mutableStateMapOf
    • 复杂对象 → mutableStateOf + Saver
  4. 是否依赖其他状态?
    • 是 → derivedStateOf
    • 否 → 直接使用
  5. 数据来源?
    • ViewModel/Flow → collectAsStateWithLifecycle
    • LiveData → observeAsState
    • 本地状态 → mutableStateOf

八、最佳实践总结

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更新的值

核心要点

  1. MutableState 是一个容器:它包装了实际值,并添加了追踪能力
  2. Compose 需要这个容器:才能知道什么时候需要重组
  3. 性能权衡:用少量内存和计算开销换取响应式更新
  4. 只在必要时使用:只有影响UI的状态才需要包装成 MutableState

简单来说:普通数据类型是值本身,MutableState 是带有监听能力的值容器。你需要UI响应式更新时用 MutableState,否则用普通变量。


0 条评论

发表回复

您的电子邮箱地址不会被公开。