与Android架构导航相当的startActivityForResult()

Jon*_*nas 23 android android-architecture-navigation

我有3个屏幕的工作流程.从"屏幕1"到访问"屏幕2",用户必须接受我在图片"模态"中调用的某些条款和条件.但他只需要接受这些条件一次.下次他在第一个屏幕上时,他可以直接进入屏幕2.用户可以选择不接受这些条款,因此我们返回"屏幕1"并且不要尝试转到"屏幕2".

App工作流程

我想知道如何使用新的导航组件.

以前,我会做什么:

  • 在屏幕1上,检查用户是否必须接受条件
  • 如果不是,请启动"屏幕2"活动
  • 如果是,请使用startActivityForResult()并等待模态的结果.将条款标记为已接受.开始"屏幕2"

但是使用导航图,无法启动片段来获取结果.

我可以在"模态"屏幕上标记接受的条款,然后从那里开始"屏幕2".问题是,要访问屏幕2,我需要做一个网络请求.我不想复制对API的调用并在"屏幕1"和"模态"中处理其结果.

有没有办法从"模态"回到"屏幕1"与一些信息(用户接受条款),使用Jetpack导航?

编辑:我目前通过使用Yahya建议的相同流程绕过它:使用一个仅用于模态的活动并使用startActivityForResult"屏幕1".我只是想知道我是否可以继续使用导航图来表示整个流程.

Zie*_*iem 18

1.3.0-alpha04版本的 AndroidX Fragment 库中,他们引入了允许在Fragments之间传递数据的新 API 。

添加了通过 FragmentManager 上的新 API 在两个 Fragment 之间传递结果的支持。这适用于导航中的层次结构片段(父/子)、DialogFragments 和片段,并确保结果仅在至少 STARTED 时发送到您的 Fragment。( b/149787344 )

FragmentManager 获得了两个新方法:

如何使用它?

FragmentA附加FragmentResultListenerFragmentManageronCreate方法:

setFragmentResultListener("request_key") { requestKey: String, bundle: Bundle ->
    val result = bundle.getString("your_data_key")
    // do something with the result
}
Run Code Online (Sandbox Code Playgroud)

FragmentB添加此代码返回的结果:

val result = Bundle().apply {
    putString("your_data_key", "Hello!")
}
setFragmentResult("request_key", result)
Run Code Online (Sandbox Code Playgroud)

开始FragmentB例如:通过使用:

findNavController().navigate(NavGraphDirections.yourActionToFragmentB())
Run Code Online (Sandbox Code Playgroud)

关闭/结束FragmentB通话:

findNavController().navigateUp()
Run Code Online (Sandbox Code Playgroud)

现在,您FragmentResultListener应该会收到通知,并且您应该会收到结果。

(我fragment-ktx用来简化上面的代码)


小智 15

最近(在 androidx-navigation-2.3.0-alpha02 中)Google 发布了一种使用片段实现此行为的正确方法。

简而言之:(来自发行说明)

如果Fragment A需要结果来自Fragment B..

A应该从currentBackStackEntry获取 savedStateHandle ,调用 getLiveData 提供一个键并观察结果。

findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<Type>("key")?.observe(
    viewLifecycleOwner) {result ->
    // Do something with the result.
}
Run Code Online (Sandbox Code Playgroud)

B应该从previousBackStackEntry 中获取 savedStateHandle ,并使用与 LiveData 中的 LiveData 相同的键设置结果A

findNavController().previousBackStackEntry?.savedStateHandle?.set("key", result)
Run Code Online (Sandbox Code Playgroud)

相关文档

  • 如果我的“活动 A”需要“活动 B”的结果怎么办?我相信这行不通,因为两个活动中的“navController”不同? (3认同)

Ant*_*hon 14

共享视图模型有两种选择。

  1. 有趣的navigationBackWithResult(结果:捆绑包),如此处所述https://medium.com/google-developer-experts/using-navigation-architecture-component-in-a-large-banking-app-ac84936a42c2

  2. 创建一个回调。

ResultCallback.kt

interface ResultCallback : Serializable {
    fun setResult(result: Result)
}
Run Code Online (Sandbox Code Playgroud)

将此回调作为参数传递(请注意,它必须实现Serializable,并且接口需要在其自己的文件中声明。)

<argument android:name="callback"
                  app:argType="com.yourpackage.to.ResultCallback"/>
Run Code Online (Sandbox Code Playgroud)

使framgent A实现ResultCallback,片段B by将获取参数并将数据通过args.callback.setResult(x)传递回去

  • 这对我来说非常有效,我认为这是最好的解决方案,直到应用程序在目标片段上进入后台并因“NotSerializedException”而崩溃。 (2认同)

LaV*_*epe 10

看来目前startActivityForResult导航组件中没有对应的功能。但是,如果您正在使用LiveData和ViewModel,则可能对本文感兴趣。作者使用活动范围的ViewModel和LiveData来实现片段。

  • 对。Google已在此bug https://issuetracker.google.com/issues/79672220中确认了这一点。 (2认同)