Appearance
page-result-demo
1. 实验目标
验证「子页面选完结果回传父页面」的最小正确写法,避免把一次性回传结果升级成全局状态:
- 子页用
setResult(RESULT_OK, intent)+finish()回传EXTRA_RESULT - 父页用
registerForActivityResult接收结果,只更新本页展示 - 区分「页面回传结果」与
SavedStateHandle恢复态的边界
2. 对应事故样板
- 为什么地址选择 / 支付结果不该塞进全局单例?
- 一句话答:回传结果是页面间的一次性契约,父页收到后应落到本页 state;升级成全局状态会污染其他页面并难以清理。
- 什么时候才该用
SavedStateHandle而不是EXTRA_RESULT?- 一句话答:
EXTRA_RESULT适合 Activity 栈内父子回传;SavedStateHandle适合进程恢复时重建轻量锚点,不适合承载「刚选完要立刻消费」的脉冲结果。
- 一句话答:
3. 运行方式
bash
cd labs/android/host
./gradlew installDebug打开 Android Host → 打开页面返回结果实验室(由 host 入口接线后可见)。
4. 观察步骤
- 首页点击「打开详情页选择结果」
- 详情页点击「携带结果返回」
- 回到首页,观察「上次返回结果」区域更新
- 再次打开详情并取消(按返回键不点按钮):首页结果应保持不变
5. 关键实现速览
5.1 子页回传结果
kotlin
val resultIntent = Intent().putExtra(EXTRA_RESULT, "detail-result-$selectionId")
setResult(RESULT_OK, resultIntent)
finish()这段代码说明:回传结果走 Intent extra,生命周期随 Activity 结束而交付给父页 launcher。
完整源码:PageResultDetailActivity.kt
5.2 父页注册 launcher 接收
kotlin
private val detailLauncher = registerForActivityResult(
ActivityResultContracts.StartActivityForResult(),
) { result ->
if (result.resultCode == RESULT_OK) {
val value = result.data?.getStringExtra(PageResultDetailActivity.EXTRA_RESULT)
if (value != null) {
lastResultView.text = "上次返回结果:$value"
}
}
}这段代码说明:父页只在回调里更新本页 UI,不把回传结果写入全局仓库或 SavedStateHandle。
完整源码:PageResultDemoActivity.kt
5.3 SavedStateHandle 边界(对照)
若结果需要跨进程恢复(例如筛选条件 key),才进入 SavedStateHandle;页面刚选完的回传结果应在父页 onActivityResult / launcher 回调中立刻消费,不应持久化到恢复态,否则进程重建后可能重复应用旧选择。
6. 对应知识库文档
- 理论主文档:ViewModel 架构、SavedStateHandle 与进程被杀恢复
- 状态分层总览:状态管理、路由、架构