目录
一、remember 家族概览
remember 相关 API
├── remember() // 基础:重组后保持值
├── remember(key) // 带键:key变化时重新计算
├── rememberSaveable() // 配置变更后保持
├── rememberCoroutineScope() // 记住协程作用域
├── rememberUpdatedState() // 记住最新值(用于副作用)
├── remember { mutableStateOf() } // 记住状态(最常用组合)
└── derivedStateOf() // 记住派生状态(相关但独立)
| API | 作用 | 生命周期 | 适用场景 | 示例 |
|---|---|---|---|---|
remember() |
存储值 | 重组后保持 | 普通状态、对象缓存 | val data = remember { loadData() } |
remember(key) |
条件存储 | key变化时刷新 | 依赖外部参数的计算 | val user = remember(userId) { loadUser(userId) } |
rememberSaveable() |
持久化存储 | 配置变更后保持 | 表单输入、UI状态 | var text by rememberSaveable { mutableStateOf("") } |
rememberCoroutineScope() |
协程作用域 | 跟随组合 | 在点击事件中启动协程 | val scope = rememberCoroutineScope() |
rememberUpdatedState() |
最新值引用 | 始终更新 | 副作用中捕获最新回调 | val callback by rememberUpdatedState(onClick) |
derivedStateOf() |
派生状态 | 依赖变化时 | 计算属性 | val isValid by remember { derivedStateOf { text.length > 3 } } |
二、特别说明
remember
var count by remember { mutableStateOf(0) }
var text by remember { mutableStateOf("") }
// ❌ 问题:每次重组都重新计算
val isEven = count % 2 == 0 // 即使 count 没变也会计算
// ❌ 问题:用 remember 但依赖不对
val isOdd = remember { count % 2 != 0 } // count 变化时不会更新!
rememberSaveable
- 什么是配置变更
"任何导致 Activity 重建的场景都是配置变更,都需要 rememberSaveable 来保持用户状态"
配置变更包括但不限于:
| 类型 | 示例 | 是否需要 rememberSaveable |
|---|---|---|
| 屏幕方向 | 旋转手机 | ✅ 是 |
| 语言区域 | 切换中英文 | ✅ 是 |
| 深色模式 | 开启夜间主题 | ✅ 是 |
| 字体大小 | 调整系统字体 | ✅ 是 |
| 屏幕尺寸 | 进入分屏 | ✅ 是 |
| 折叠状态 | 折叠屏展开 | ✅ 是 |
| 键盘连接 | 外接键盘 | ✅ 是 |
| 进程杀死 | 系统回收内存 | ✅ 是 |
- 能存什么?怎么存?
1. 基本类型 - 自动存
kotlin
var count by rememberSaveable { mutableIntStateOf(0) }
var text by rememberSaveable { mutableStateOf("") }
var flag by rememberSaveable { mutableStateOf(false) }
2. 可打包对象 - @Parcelize
kotlin
@Parcelize
data class User(
val name: String,
val age: Int
) : Parcelable
@Composable
fun UserScreen() {
var user by rememberSaveable {
mutableStateOf(User("Alice", 25)) // ✅ 自动保存
}
}
3. 复杂对象 - 自定义 Saver
- 与 remember 的对比
| 特性 | remember | rememberSaveable |
|---|---|---|
| 重组后保持 | ✅ 能 | ✅ 能 |
| 屏幕旋转后 | ❌ 不能 | ✅ 能 |
| 进程杀死后 | ❌ 不能 | ✅ 能(系统自动保存 Bundle) |
| 存储位置 | 内存中的组合树 | Bundle + 内存 |
| 存储容量 | 无限制 | 受 Bundle 大小限制 |
| 性能开销 | 小 | 稍大(需要序列化) |
- 应用场景
"用户填的表单、选的 Tab、展开的项目,都应该用 rememberSaveable"
rememberCoroutineScope
rememberCoroutineScope() 返回一个与当前 Composable 生命周期绑定的协程作用域。
rememberUpdatedState
- 与remember的对比
| 特性 | remember |
rememberUpdatedState |
|---|---|---|
| 用途 | 存储值 | 获取最新值(在副作用中) |
| 触发重组 | ✅ 会 | ❌ 不会 |
| 更新时机 | 值变化时 | 只更新内部引用 |
| 典型场景 | UI 状态 | 回调、长时间运行的协程 |
| 返回值 | 可变或只读 | 只读 State |
- 应用场景
rememberUpdatedState不是用来获取最新值,而是用来确保执行的是最新的函数/回调!
| 场景 | 是否需要 rememberUpdatedState | 原因 |
|---|---|---|
| 读取变量值 | ❌ 不需要 | Kotlin 闭包捕获引用 |
| 调用动态函数 | ✅ 需要 | 函数对象本身可能变化 |
| 使用 lambda 参数 | ✅ 需要 | lambda 可能被替换 |
| 监听器/回调 | ✅ 需要 | 监听器实现可能变化 |
derivedStateOf
"复杂计算、组合状态、条件逻辑,需要用 derivedStateOf 来优化性能"
0 条评论