如何使用Android导航组件将一个值传回到之前的Fragment目的地?

15

假设我有这样一些目的地

从片段A --> 到片段B --> 到片段C

我可以使用Safe Args将数据从片段A传递到片段B,也可以使用Safe Args从片段B传递到片段C。

如果我想把在片段C生成的字符串带回到片段B或片段A怎么办?

要从片段C导航到片段B,我使用以下代码:

Navigation.findNavController(fragmentView).navigateUp()

我使用以下代码从片段C导航到片段A:

Navigation.findNavController(view).popBackStack(R.id.fragmentA, false)

那么如何将一个值传回到之前的片段目标?我需要从片段C返回到片段B并通过安全参数传递该值吗?

非常需要你的帮助。非常感谢:)


@ghita 那我该怎么办?你有没有遇到这个问题? - Alexa289
我仍然被这个问题困扰,正在考虑解决方案... - ghita
@ghita,也许我会尝试使用监听器,请告诉我如果你的问题有答案 :) - Alexa289
1
我已经使用了popBackStack和SharedPrefs。如果我找到更好的解决方案,我会在这里发帖。如果您找到更好的解决方案,请也分享一下,谢谢。 - ghita
显示剩余3条评论
3个回答

21
您可以使用以下代码片段将数据发送到上一个片段。
观察数据的片段A:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe(viewLifecycleOwner) { data ->
        // Do something with the data.
    }
}

片段B发送数据:

findNavController().previousBackStackEntry?.savedStateHandle?.set("key", data)
findNavController().popBackStack()

我也为此编写了扩展程序。
fun <T : Any> Fragment.setBackStackData(key: String,data : T, doBack : Boolean = true) {
    findNavController().previousBackStackEntry?.savedStateHandle?.set(key, data)
    if(doBack)
    findNavController().popBackStack()
}

fun <T : Any> Fragment.getBackStackData(key: String, result: (T) -> (Unit)) {
    findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<T>(key)?.observe(viewLifecycleOwner) {
        result(it)
    }
}

使用方法:

片段 A:

getBackStackData<String>("key") { data ->
    // Do something with the data.
}

片段 B:

setBackStackData("key",data)

    

注意:我正在使用字符串作为数据。你可以使用任何其他类型的变量。
注意:如果你要使用类作为数据,请不要忘记添加@Parcelize注解并扩展Parcelable

如果立即有结果,完美的话,请将 .getLiveData<String>("key")?.observe(viewLifecycleOwner) { data -> 替换为 .get<String>("data") - Fortran
我们能否将游戏状态(例如:暂停)发送到前一个片段,并在再次启动该片段时显示相同的UI状态? - Chandu
@Chandu 是的,你可以发送任何数据类型。只需声明数据类型并使用它。 enum class GameState {} ... setBackStackData("state",GameState.Paused) ... getBackStackData<GameState>("state") ... - Amir
1
以上解决方案运行无误。 - Pankaj Jangid
1
令人惊叹的扩展 :) - undefined

0

我刚遇到了同样的问题,我可以提出几个选项(目前正在考虑哪一个最适合我的用例)。

  1. 从片段 C 创建导航操作返回到片段 A。请注意,如果您只这样做,您的堆栈现在将是:A-B-C-A。为了避免这种情况,您可以使用 popUpToPopUpToInclusive。请参阅 文档

这种方法的缺点是无论如何片段 A 都会被清除,并且必须重新加载(并再次获取所有数据)。

  • 在你的片段之间使用共享的ViewModel,并使用LiveData观察所需的值。在这种情况下,片段C将在共享的ViewModel中更新一个LiveData值,而片段A会观察到。现在当你回到片段A时,你的observer将被设置为由片段C设置的值。

  • 与选项2类似,如果您正在使用外部数据源(如Room数据库),则可以在片段A中使用LiveData观察更改。在这种情况下,片段C所要做的就是更新数据源,而片段A将通过LiveData自动更新


  • 0

    你的回答可以通过添加更多支持信息来改进。请[编辑]以添加更多详细信息,例如引用或文档,以便他人可以确认您的答案是否正确。您可以在[帮助中心](/ help / how-to-answer)中找到有关如何编写良好答案的更多信息。 - Community

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接