概论
Compose的UI更新,依赖,状态驱动UI更新的思想。 Compose 的状态驱动 UI 思想:
UI = f(state)
当 state 发生变化时,Compose 会自动重新调用相关的 @Composable 函数,只更新有变化的部分。这就是为什么 mutableStateOf(...) 是 Compose 中管理 UI 状态的关键。
Compose 状态的原理简图:
remember {
mutableStateOf("Hello")
}
↓
→ 构建时保存状态
→ 当状态 .value 改变
→ Compose 标记该 UI 为 “脏”
→ 在下一个帧(frame)中进行 Recomposition(重新组合)
→ 只重组使用该状态的 Composable
使用方式
val mutableState = remember { mutableStateOf(default) }
🔍 说明:
mutableState是一个MutableState<T>对象,它有.value属性。- 状态改变需要手动
.value = ... - 使用方式:
val nameState = remember { mutableStateOf("John") }
TextField(
value = nameState.value,
onValueChange = { nameState.value = it }
)
② var value by remember { mutableStateOf(default) }
🔍 说明:
- 使用 Kotlin 的 属性委托(
by)语法糖 - 编译器会自动导入
.value的 getter 和 setter - 使用方式:
var name by remember { mutableStateOf("John") }
TextField(
value = name,
onValueChange = { name = it }
)
✅ 优点:
- 简洁、易读,是 Compose 中最常用的方式
- 推荐用于局部状态(如按钮状态、输入框值等)
⚠️ 关键导入(别忘记):
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
③ val (value, setValue) = remember { mutableStateOf(default) }
🔍 说明:
- Kotlin 的解构写法(适用于
MutableState是component1()/component2()支持的) value是状态值,setValue()是设置方法
val (name, setName) = remember { mutableStateOf("John") }
TextField(
value = name,
onValueChange = { setName(it) }
)
✅ 优点:
- 语义清晰,适合函数式风格(像 React 的
useState) - 可作为参数传递给组件(回调函数)
⚠️ 注意:
- 虽然解构写法是有效的,但在 Compose 中用得相对较少,除非你习惯这种写法。
配置变更后的状态保存
rememberSaveable 是 Jetpack Compose 提供的一个用于自动保存和恢复状态的 API,特别适合在 屏幕旋转 或 进程重建 后保留用户界面状态。
✅ 简洁定义
rememberSaveable=remember+ 自动保存/恢复状态
底层是通过SavedStateHandle或Bundle实现的。
🧪 使用方式
✅ 基本用法:
var name by rememberSaveable { mutableStateOf("") }
-
当用户输入内容后,即使旋转屏幕,输入值也不会丢失;配置变更后,经历了保存,恢复的过程。
-
相比之下,
remember就会失效。
✅ 使用列表或复杂结构
对于 List<String>、Map 等结构也可以用:
var items by rememberSaveable { mutableStateOf(listOf("A", "B")) }
但注意:数据类型必须是可序列化的(如 String, Int, List)
❌ 不支持的类型(默认情况下)
rememberSaveable 默认使用 Bundle 存储状态,因此不支持保存如下类型:
- 自定义类(除非实现了
Parcelable/Serializable) - 高阶函数(Lambda)
- 非可序列化对象(如某些 ViewModel 状态)
✅ 支持自定义类型保存(高级用法)
可以通过 Saver 来让 rememberSaveable 保存自定义对象:
data class User(val name: String, val age: Int)
val UserSaver = Saver<User, List<Any>>(
save = { listOf(it.name, it.age) },
restore = { User(it[0] as String, it[1] as Int) }
)
var user by rememberSaveable(saver = UserSaver) {
mutableStateOf(User("Tom", 20))
}
代码含义解释:状态变量是user,类型为User;该状态变量的保存和恢复的定义,由UserSaver来定义。具体的说,每个状态变量,保存到list表中,由save方法实现;每个状态变量的恢复,值从list中获取,由restore方法实现。
📌 remember vs rememberSaveable 对比
| 特性 | remember | rememberSaveable |
|---|---|---|
| 作用周期 | 仅当前组合过程 | 配置变更中保持(如旋转) |
| 可恢复能力 | ❌ 不可恢复 | ✅ 自动保存和恢复 |
| 可保存类型 | 任意类型 | 只能保存基本类型、可序列化对象 |
| 原理 | 存在于内存中 | 存入 Bundle/ViewModelState |
## 📍适用场景
| 适用场景 | 是否使用 rememberSaveable |
|---|---|
| 表单输入(用户名、搜索框) | ✅ 是,避免旋转丢失输入 |
| Tab切换状态 | ✅ 保存当前Tab索引 |
| 页面滚动位置 | ✅ 保存列表偏移量 |
| 一次性 UI 逻辑(临时变量) | ❌ 用 remember 即可 |
| 大对象/复杂业务状态 | ❌ 推荐使用 ViewModel |
✅ 示例对比:旋转屏幕是否保留状态
// 旋转后丢失
var count by remember { mutableStateOf(0) }
// 旋转后保留
var count by rememberSaveable { mutableStateOf(0) }