SavedStateHandle无法从LiveData恢复数据:锁屏后导航结果无回调
问题分析与解决方案
核心原因
锁屏后应用进入后台,系统可能触发进程回收或导航栈实例销毁,导致两个关键问题:
navController.previousBackStackEntry返回null,无法将结果写入目标Fragment的SavedStateHandle;- 进程重启后,
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
相关产品推荐
相关产品推荐

