Appearance
state-persistence-demo
1. 实验目标
验证最容易在列表页与表单页里写乱的“三层恢复”:
- 内存态:分页游标放 ViewModel,只抗旋转,不抗进程死亡
- 恢复态:筛选条件放
SavedStateHandle,用于进程恢复时重建查询入口 - 持久态:草稿正文落 DataStore,冷启动后仍能回补
2. 对应事故样板
- 为什么列表页经常“条件丢了但列表又重刷一遍”?
- 一句话答:筛选条件没有进入恢复态,进程恢复后失去查询锚点,只能回到默认条件重新请求。
- 为什么草稿页切后台回来经常只剩一个 ID,没有正文?
- 一句话答:正文不该塞进 Bundle;正确做法是恢复态只存锚点,正文落盘后再回补。
3. 运行方式
bash
cd labs/android/host
./gradlew installDebug打开 Android Host → 打开状态恢复态 / DataStore 实验室。
4. 观察步骤
- 输入筛选词并点击“更新筛选条件”
- 点击“分页 +1”“记录滚动锚点”
- 输入草稿正文并点击“写入 DataStore 草稿”
- 旋转屏幕:页码和筛选条件仍在
- 开发者选项开启 Don't keep activities 后切后台再回来:
- 筛选条件仍能恢复
- 草稿正文可从 DataStore 回补
- 分页游标需重新计算(演示内存态边界)
5. 关键实现速览
5.1 恢复态只放轻量锚点
kotlin
val filter: String
get() = savedStateHandle[KEY_FILTER] ?: ""
fun updateFilter(newFilter: String) {
savedStateHandle[KEY_FILTER] = newFilter
}这段代码说明:恢复态只放“重建查询所需的 key”,而不是把整页结果塞进 Bundle。
完整源码:StatePersistenceDemoActivity.kt
5.2 正文落盘,恢复时再回补
kotlin
suspend fun saveDraft(value: String) {
activity.demoDataStore.edit { it[draftKey] = value }
}
suspend fun readDraft(): String {
return activity.demoDataStore.data.first()[draftKey] ?: ""
}这段代码说明:真正要跨冷启动保真的内容,应进入 DataStore,而不是依赖 SavedStateHandle。
完整源码:StatePersistenceDemoActivity.kt
6. 对应知识库文档
- 理论主文档:状态持久化、内存恢复与分层恢复策略
- 状态分层总览:状态管理、路由、架构