compose中 remember retain rememberSaveable、rememberSerializable的区别

Jetpack Compose 状态生命周期说明文档

(remember / retain / rememberSaveable / rememberSerializable)

本文基于 Google 官方 Compose 文档
State lifespans in Compose


一、为什么需要这些 API?

Compose 中的状态,默认是短命的

kotlin 复制代码
val x = 0
  • 每次重组都会重新执行
  • Activity 重建后一定丢失
  • 进程被杀后完全消失

为了解决 "状态应该活多久" 的问题,Compose 提供了不同层级的状态保存机制。


二、状态生命周期总览(先看结论)

API 跨重组 跨配置变化(旋转等) 进程被杀后恢复 核心特点
remember 只对抗重组
retain 保持同一个实例
rememberSaveable 基于 SavedState
rememberSerializable 基于 kotlinx.serialization

三、remember

1️⃣ 定义

在当前 Composition 中缓存一个值,避免重组时重新创建

kotlin 复制代码
val state = remember { mutableStateOf(0) }

2️⃣ 生命周期

  • ✅ 重组(Recomposition)
  • ❌ Activity 重建
  • ❌ 进程被杀

Composable 离开 Composition,状态就消失


3️⃣ 典型使用场景

✅ UI 临时状态

✅ 动画状态

✅ 只和当前 Composable 有关的状态

kotlin 复制代码
@Composable
fun ExpandableCard() {
    var expanded by remember { mutableStateOf(false) }
    ...
}

4️⃣ 不要用在这里

❌ 用户输入

❌ Tab 选中状态

❌ 滚动位置

❌ 需要跨旋转保存的状态


四、retain(官方 API,容易被忽略)

1️⃣ 定义

在配置变化时保留同一个对象实例(不做序列化)

kotlin 复制代码
val player = retain {
    ExoPlayer.Builder(appContext).build()
}

2️⃣ 生命周期

  • ✅ 重组
  • ✅ Activity 重建(旋转等)
  • ❌ 进程被杀

⚠️ 不会保存到 Bundle,不会 restore


3️⃣ retain 的核心语义(非常重要)

"保持同一个实例(===)"

  • 不重新创建
  • 不做序列化
  • 类似 onRetainNonConfigurationInstance

4️⃣ 适合的对象类型

✅ 不能序列化的大对象

✅ 播放器(ExoPlayer)

✅ 缓存、控制器、引擎

✅ Flow / Channel / 协程相关对象


5️⃣ retain 的铁律(必须遵守)

不能引用 Activity / Fragment / View / Lifecycle

kotlin 复制代码
// ❌ 错误
retain { MyManager(activity) }
kotlin 复制代码
// ✅ 正确
retain { MyManager(applicationContext) }

五、rememberSaveable

1️⃣ 定义

在 remember 的基础上,把状态保存到 SavedStateRegistry

kotlin 复制代码
var count by rememberSaveable { mutableStateOf(0) }

2️⃣ 生命周期

  • ✅ 重组
  • ✅ 配置变化
  • ✅ 进程被杀后恢复

3️⃣ 默认支持的数据类型

  • Int / Long / Boolean
  • String
  • Parcelable
  • Serializable

4️⃣ 自定义对象(Saver)

kotlin 复制代码
data class UiState(val a: Int, val b: Int)

val state = rememberSaveable(
    saver = listSaver(
        save = { listOf(it.a, it.b) },
        restore = { UiState(it[0], it[1]) }
    )
) {
    UiState(0, 0)
}

5️⃣ 典型使用场景

✅ 用户输入

✅ Tab / 页面选中状态

✅ 滚动位置

✅ 表单数据


六、rememberSerializable(官方 API)

1️⃣ 定义

专门为 kotlinx.serialization 提供的 rememberSaveable 变体

kotlin 复制代码
@Serializable
data class UserUiState(
    val name: String,
    val age: Int
)

val state = rememberSerializable {
    UserUiState("", 0)
}

2️⃣ 生命周期

  • ✅ 重组
  • ✅ 配置变化
  • ✅ 进程被杀后恢复

3️⃣ 和 rememberSaveable 的区别

对比点 rememberSaveable rememberSerializable
保存机制 Bundle + Saver kotlinx.serialization
是否写 Saver 可能需要 不需要
适合对象 Android 风格 纯 Kotlin 数据

4️⃣ 适合的项目类型

✅ MVI / Redux

✅ 纯数据 UI State

✅ 跨平台 / KMP 项目


七、官方推荐使用顺序(经验法则)

UI 状态选择优先级

复制代码
ViewModel(业务状态)
↓
rememberSaveable / rememberSerializable(用户状态)
↓
retain(不可序列化的长期对象)
↓
remember(临时 UI 状态)

八、你作为 Android 工程师应该怎么用?

常见场景对照表

场景 正确选择
动画展开 / 收起 remember
Tab 选中 rememberSaveable
输入框内容 rememberSaveable
播放器 / 引擎 retain
UI State(data class) rememberSerializable
网络数据 ViewModel

九、一句话总结(定锚点)

  • remember:对抗重组
  • retain:保持实例,跨配置
  • rememberSaveable:SavedState
  • rememberSerializable:序列化 UI State

相关推荐
换元不配限4 天前
Jetpack Compose 副作用
compose·jetpack compose·附带效应·副作用·launchedeffect·sideeffect·composable生命周期
Jomurphys4 天前
Compose 适配 - 自适应布局(窗口大小类 WindowSizeClasses、列表详情、辅助窗格)
android·compose
Jomurphys4 天前
Compose 适配 - 分辨率(密度)
android·compose
换元不配限9 天前
Jetpack Compose 状态管理指南
android·状态管理·compose·状态·单向数据流·jetpack compose·状态容器
Android-Flutter20 天前
android compose shadow 阴影 使用
android·kotlin·compose
Android-Flutter20 天前
android compose 自定义Painter绘制图形 使用
android·kotlin·compose
Android-Flutter21 天前
android compose Brush 渐变和着色器 使用
android·kotlin·compose
至乐活着1 个月前
Docker Compose多服务编排实战:从零搭建Node.js+MySQL+Redis全栈应用
docker·微服务·devops·容器编排·compose
le1616162 个月前
Android Compose——尺寸修饰符的调用顺序构成的不同尺寸约束效果
android·compose·modifier
le1616162 个月前
Android Compose Modifier修饰符
android·compose·modifier