使用Android Navigation将数据传递回上一个Fragment

46

我开始使用Android架构组件(导航和安全参数、视图模型)以及Koin库。

目前,我在传递两个片段之间的参数时遇到了问题 - 我需要将一个字符串值从片段A传递到片段B,在片段B中修改此值并将其传回片段A。

我找到了解决我的问题的一个可能的方法 - 共享视图模型。不幸的是,这种方法有一个问题,因为我可以在屏幕之间传递和修改值,但当片段A导航到另一个目标时,共享视图模型中的值仍然被存储而没有清除。

在Android Navigation中是否有任何不同的解决方法来传递和修改数据? 我想避免手动清除这个值(当片段A被销毁时)。


你解决了吗? - user924
寻找类似情况的解决方案。 如果已经解决,请更新? - Faisal
1
请参阅 https://dev59.com/XlUL5IYBdhLWcg3wKlV1。基本上,共享一个ViewModel即可。 - Graham Perks
请查看这里的答案。他们最近刚刚添加了导航库的功能。 - LeHaine
5个回答

72

Android 刚刚发布了一个解决方案;在目的地之间传递数据 (Navigation 2.3.0-alpha02),基本上,在片段 A 中,您观察变量的更改,在片段 B 中,在执行 popBackStack() 之前更改该值。

片段 A:

findNavController().currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe(viewLifecycleOwner) { result ->
    // Do something with the result.
}

片段 B:

navController.previousBackStackEntry?.savedStateHandle?.set("key", result)
navController.popBackStack()

谢谢!它可以工作,但与从片段A传递数据到片段B时相比,这是非常奇怪的解决方案。这个解决方案更像是使用bundle传递数据的旧方法,就像我们在Java中习惯做的那样。 - Zeeshan
我们可以使用这个传递多个数据吗? - Richa
干得好!!!继续保持 - VVB
8
注意:Hilt注入ViewModel中的SavedStateHandle和NavBackStackEntry SavedStateHandle不是同一个对象。我花了几个小时才搞清楚这一点。 - t3ddys
我需要在Viewmodel中有一个onBackPressed事件的方法。我搜索了很多小时,这是正确的方法。 - Chucky
显示剩余2条评论

2
您可以使用Fragment Result API。
Fragment A -> Fragment B
在Fragment A中:
binding.buttonGo.setOnClickListener {
   setFragmentResultListener(ADD_LOCATION) { key, bundle ->
       clearFragmentResultListener(requestKey = ADD_LOCATION)
       val selectedLocationModel =
           bundle.getParcelable<LocationModel>(SELECTED_LOCATION_MODEL)
       this.selectedLocationModel = selectedLocationModel
   }
   navToFragmentB()
}

在片段B中:
setFragmentResult(
    ADD_LOCATION,
    bundleOf(SELECTED_LOCATION_MODEL to selectedLocationModel)
)
goBack()

不要忘记在创建新的监听器之前调用clearFragmentResultListener()

1
目前,我在两个片段之间传递参数遇到了问题 - 我需要从片段A传递一个字符串值到片段B,在片段B中修改这个值并将其传回片段A。
理论上的解决方案是将两个片段放在共享的< navigation >标签中,然后将ViewModel范围限定为导航标签的ID,这样您现在在两个屏幕之间共享ViewModel。
为了使其可靠,最好使用Navigation标记的NavBackStackEntry作为ViewModelStoreOwner和SavedStateRegistryOwner,并创建一个AbstractSavedStateViewModelFactory,该工厂将使用ViewModelProvider创建ViewModel,同时还提供SavedStateHandle。
您可以使用与共享ViewModel关联的此SavedStateHandle将结果从FragmentB传达到FragmentA(范围限定为共享的NavGraph)。

0
你可以尝试这个解决方案。
<fragment
    android:id="@+id/a"
    android:name="...">

    <argument
        android:name="text"
        app:argType="string" />

    <action
        android:id="@+id/navigate_to_b"
        app:destination="@id/b" />

</fragment>

<fragment
    android:id="@+id/b"
    android:name="...">

    <argument
        android:name="text"
        app:argType="string" />

    <action
        android:id="@+id/return_to_a_with_arguments"
        app:destination="@id/a"
        app:launchSingleTop="true"
        app:popUpTo="@id/b"
        app:popUpToInclusive="true" />

</fragment>

和导航片段

NavHostFragment.findNavController(this).navigate(BFragmentDirections.returnToAWithArguments(text))

ianhanniballake的评论帮助我解决了一个类似的问题


-7

1) 使用 action_A_to_B 和 SafeArgs 将字符串从 Fragment A 传递到 Fragment B。

2) 使用 popBackStack 方法移除 Fragment B。

navController.popBackStack(R.id.AFragment, false);

或者

navController.popBackStack();

3) 然后使用 action_B_to_A 将修改后的数据从 B 传递到 A。

编辑。

这里有另一个解决方案


你的回答并没有解决传递参数的问题,它只是从NavController中移除了片段而已。请重新考虑你的回答。 - Duna

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