到目前为止,我仅使用导航组件就可以成功导航到对话框并返回。问题是,我必须在对话框中做一些事情,然后将结果返回到调用对话框的片段中。
一种方法是使用共享的viewmodel。但是为此,我必须使用.of(activity),即使我不再需要它,也使我的应用仅占用内存。
另一种方法是重写show(fragmentManager,id)方法,获取对片段管理器的访问,并从中访问先前的片段,然后可以将其设置为targetfragment。在实现回调接口之前,我已经使用了targetFragment方法,因此我的对话框可以将结果通知给TargetFragment。但是在导航组件方法中,它感觉很笨拙,并且可能在某一点或另一点停止工作。
还有其他方法可以做我想要的吗?也许有一种方法可以解决第一种方法的问题?
答案 0 :(得分:7)
在Navigation 2.3.0-alpha02及更高版本中,NavBackStackEntry允许访问SavedStateHandle。 SavedStateHandle是一个键值映射,可用于存储和检索数据。这些值会在进程终止(包括配置更改)时保持不变,并通过同一对象保持可用。通过使用给定的SavedStateHandle,您可以在目标之间访问和传递数据。这是一种有用的机制,它是一种将数据从堆栈中弹出后从目的地取回数据的机制。
要将数据从目标B传递回目标A,首先将目标A设置为在其SavedStateHandle上侦听结果。为此,请使用getCurrentBackStackEntry()API检索NavBackStackEntry,然后观察SavedStateHandle提供的LiveData。
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val navController = findNavController();
// We use a String here, but any type that can be put in a Bundle is supported
navController.currentBackStackEntry?.savedStateHandle?.getLiveData("key")?.observe(
viewLifecycleOwner) { result ->
// Do something with the result.
}
}
在目标B中,必须使用getPreviousBackStackEntry()API在目标A的SavedStateHandle上设置结果。
navController.previousBackStackEntry?.savedStateHandle?.set("key", result)
答案 1 :(得分:4)
感谢@NataTse和official docs,我想出了扩展名,希望可以写出更少的样板代码:
fun <T>Fragment.setNavigationResult(key: String, value: T) {
findNavController().previousBackStackEntry?.savedStateHandle?.set(
key,
value
)
}
fun <T>Fragment.getNavigationResult(@IdRes id: Int, key: String, onResult: (result: T) -> Unit) {
val navBackStackEntry = findNavController().getBackStackEntry(id)
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME
&& navBackStackEntry.savedStateHandle.contains(key)
) {
val result = navBackStackEntry.savedStateHandle.get<T>(key)
result?.let(onResult)
navBackStackEntry.savedStateHandle.remove<T>(key)
}
}
navBackStackEntry.lifecycle.addObserver(observer)
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
navBackStackEntry.lifecycle.removeObserver(observer)
}
})
}
答案 2 :(得分:2)
当您将“导航组件”与对话框一起使用时,这部分代码看起来不太好(对我而言,它什么也没返回)
navController.currentBackStackEntry?.savedStateHandle?.getLiveData("key")?.observe(
viewLifecycleOwner) { result ->
// Do something with the result.}
您需要尝试从official docs出发,这对我有很大帮助
这部分对我有用:
val navBackStackEntry = navController.getBackStackEntry(R.id.target_fragment_id)
// Create observer and add it to the NavBackStackEntry's lifecycle
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_RESUME
&& navBackStackEntry.savedStateHandle.contains("key")
) {
val result =
navBackStackEntry.savedStateHandle.get<Boolean>("key")
// Do something with the result
}
}
navBackStackEntry.lifecycle.addObserver(observer)
// As addObserver() does not automatically remove the observer, we
// call removeObserver() manually when the view lifecycle is destroyed
viewLifecycleOwner.lifecycle.addObserver(LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_DESTROY) {
navBackStackEntry.lifecycle.removeObserver(observer)
}
})
在对话框中:
navController.previousBackStackEntry?.savedStateHandle?.set(
"key",
true
)