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

时间:2018-06-05 14:29:55

标签: android android-architecture-navigation

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

App workflow

我想知道如何使用新的navigation component

以前,我会做什么:

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

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

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

有没有办法使用Jetpack导航从“模态”返回到“屏幕1”并提供一些信息(用户接受条款)?

编辑:我目前通过使用Yahya建议的相同流程绕过它:使用仅适用于模态的活动并使用“屏幕1”中的startActivityForResult。我只是想知道我是否可以继续使用导航图进行整个流程。

6 个答案:

答案 0 :(得分:14)

最近(在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.
}

B应该从 previousBackStackEntry 中获取savedStateHandle,并使用与A

中的LiveData相同的键来设置结果。
findNavController().previousBackStackEntry?.savedStateHandle?.set("key", result)

Related documentation

答案 1 :(得分:10)

在AndroidX Fragment库的1.3.0-alpha04版中,他们引入了新的API,这些API允许在import Component from "./Component.js" s之间传递数据。

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

Cannot find module 'next/link'获得了两种新方法:

如何使用它?

Fragment中,通过FragmentManager方法将FragmentA添加到FragmentResultListener

FragmentManager

onCreate中添加以下代码以返回结果:

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

例如,使用以下命令开始FragmentB

val result = Bundle().apply {
    putString("your_data_key", "Hello!")
}
setFragmentResult("request_key", result)

关闭/完成FragmentB通话:

findNavController().navigate(NavGraphDirections.yourActionToFragmentB())

现在,您的FragmentB应该会收到通知,您应该会收到结果。

(我正在使用findNavController().navigateUp() 来简化上面的代码)

答案 2 :(得分:5)

现在导航组件中似乎没有startActivityForResult的等效项。但是,如果您使用LiveData和ViewModel,您可能会对this article感兴趣。作者正在使用活动范围的ViewModel和LiveData来实现片段。

答案 3 :(得分:2)

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

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

  2. 所述
  3. 创建回调。

ResultCallback.kt

ubox18@ubox18:~/ng-apps$ ng new techadda
? Would you like to add Angular routing? Yes
? Which stylesheet format would you like to use? CSS
CREATE techadda/README.md (1025 bytes)
CREATE techadda/.editorconfig (246 bytes)
CREATE techadda/.gitignore (629 bytes)
CREATE techadda/angular.json (3825 bytes)
CREATE techadda/package.json (1307 bytes)
CREATE techadda/tsconfig.json (435 bytes)
CREATE techadda/tslint.json (1621 bytes)
CREATE techadda/src/favicon.ico (5430 bytes)
CREATE techadda/src/index.html (295 bytes)
CREATE techadda/src/main.ts (372 bytes)
CREATE techadda/src/polyfills.ts (2841 bytes)
CREATE techadda/src/styles.css (80 bytes)
CREATE techadda/src/test.ts (642 bytes)
CREATE techadda/src/browserslist (388 bytes)
CREATE techadda/src/karma.conf.js (1021 bytes)
CREATE techadda/src/tsconfig.app.json (166 bytes)
CREATE techadda/src/tsconfig.spec.json (256 bytes)
CREATE techadda/src/tslint.json (244 bytes)
CREATE techadda/src/assets/.gitkeep (0 bytes)
CREATE techadda/src/environments/environment.prod.ts (51 bytes)
CREATE techadda/src/environments/environment.ts (662 bytes)
CREATE techadda/src/app/app-routing.module.ts (245 bytes)
CREATE techadda/src/app/app.module.ts (393 bytes)
CREATE techadda/src/app/app.component.css (0 bytes)
CREATE techadda/src/app/app.component.html (1152 bytes)
CREATE techadda/src/app/app.component.spec.ts (1101 bytes)
CREATE techadda/src/app/app.component.ts (212 bytes)
CREATE techadda/e2e/protractor.conf.js (752 bytes)
CREATE techadda/e2e/tsconfig.e2e.json (213 bytes)
CREATE techadda/e2e/src/app.e2e-spec.ts (637 bytes)
CREATE techadda/e2e/src/app.po.ts (251 bytes)
Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/713bc9a4'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/587a6d34'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/d24ecd3c'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/183be234'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/65378392'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/c2e18bc1'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/19e9a26f'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/14846b9a'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/1d1b4940'

Unhandled rejection Error: EACCES: permission denied, open '/home/ubox18/.npm/_cacache/tmp/fb3fc3bb'

npm ERR! cb() never called!

npm ERR! This is an error with npm itself. Please report this error at:
npm ERR!     <https://npm.community>
Package install failed, see above.

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

interface ResultCallback : Serializable {
    fun setResult(result: Result)
}

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

答案 4 :(得分:0)

还有另一种替代方法。您可以使用从模式返回到screen1的另一种导航操作,而不是使用popBackStack()。通过该操作,您可以发送任何您想要筛选的数据。使用此策略来确保模式屏幕不会再留在导航后退堆栈中:https://stackoverflow.com/a/54015319/4672107

我看到的这种策略的唯一问题是,按下后退按钮不会发送任何数据,但是大多数用例需要在特定的用户操作之后进行导航,并且在这种情况下,此解决方法将起作用。

答案 5 :(得分:0)

要获取调用者片段,请使用类似fragmentManager.putFragment(args, TargetFragment.EXTRA_CALLER, this)的内容,然后在目标片段中使用

获取调用者片段。
if (args.containsKey(EXTRA_CALLER)) {
    caller = fragmentManager?.getFragment(args, EXTRA_CALLER)
    if (caller != null) {
        if (caller is ResultCallback) {
            this.callback = caller
        }
    }
}