You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SavedStateHandle无法从LiveData恢复数据:锁屏后导航结果无回调

问题分析与解决方案

核心原因

锁屏后应用进入后台,系统可能触发进程回收或导航栈实例销毁,导致两个关键问题:

  1. navController.previousBackStackEntry返回null,无法将结果写入目标Fragment的SavedStateHandle;
  2. 进程重启后,LiveData的观察者不会自动触发已保存的数据回调,因为仅监听了后续的setValue事件。

解决方案

1. 替换previousBackStackEntry为明确的BackStackEntry定位

依赖previousBackStackEntry不可靠,需通过目标Fragment的目的地ID精准获取对应的BackStackEntry:

步骤1:启动Dialog时传递来源目的地ID

在发起Dialog的Fragment中,传递自身导航目的地ID:

val dialog = YourCustomDialogFragment()
dialog.arguments = bundleOf(
    "SOURCE_DEST_ID" to findNavController().currentDestination?.id
)
dialog.show(parentFragmentManager, "CustomDialogTag")

步骤2:修改setNavigationResult函数

通过传入的目的地ID获取正确的BackStackEntry,兜底使用previousBackStackEntry:

fun <T : Any> DialogFragment.setNavigationResult(
    result: T, key: String
) {
    val sourceDestId = arguments?.getInt("SOURCE_DEST_ID") ?: return
    val navController = findNavController()
    
    // 优先通过目的地ID获取对应BackStackEntry,避免后台回收导致previous为空
    val targetBackStackEntry = runCatching {
        navController.getBackStackEntry(sourceDestId)
    }.getOrNull() ?: navController.previousBackStackEntry
    
    targetBackStackEntry?.savedStateHandle?.set(key, result)
    dismiss()
}

2. 监听时添加初始数据检查

进程重启后,SavedStateHandle中可能已保存结果,但LiveData不会自动触发回调,需在注册监听时主动检查已有数据:

inline fun <T : Any> Fragment.registerForNavigationResult(
    key: String,
    crossinline resultEvent: (T) -> Unit
) {
    val savedStateHandle = findNavController().currentBackStackEntry?.savedStateHandle ?: return
    
    // 先检查是否已有保存的数据(进程重启后可能存在)
    savedStateHandle.get<T>(key)?.let {
        resultEvent(it)
        savedStateHandle.remove<T>(key) // 处理后移除,避免重复触发
    }
    
    // 监听后续的数据变化
    savedStateHandle.getLiveData<T>(key).observe(viewLifecycleOwner) {
        resultEvent(it)
        savedStateHandle.remove<T>(key) // 处理后清理数据
    }
}

3. 额外保障:DialogFragment保留参数

确保DialogFragment在后台重建时能保留传递的目的地ID,默认arguments会被系统自动保存,若有自定义状态可补充:

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState)
    outState.putInt("SOURCE_DEST_ID", arguments?.getInt("SOURCE_DEST_ID") ?: 0)
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    if (savedInstanceState != null) {
        arguments?.putInt("SOURCE_DEST_ID", savedInstanceState.getInt("SOURCE_DEST_ID"))
    }
}

内容的提问来源于stack exchange,提问作者Vadim Fedchuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 21:15:42