【问题标题】:Navigation Component .popBackStack() with arguments带参数的导航组件 .popBackStack()
【发布时间】:2021-07-15 07:09:24
【问题描述】:

我有两个片段。 SecondFragmentThirdFragment。实际上,我使用导航组件在片段之间传递值。像这样:

SecondFragment

val action = SecondFragmentDirections.action_secondFragment_to_thirdFragment().setValue(1)

Navigation.findNavController(it).navigate(action)

这是我从 ThirdFragment 读取值的方式:

 arguments?.let {
           val args = ThirdFragmentArgs.fromBundle(it)
           thirdTextView.text = args.value.toString()
       }

一切正常。现在我的堆栈是这样的:

ThirdFragment

SecondFragment 

有没有任何选项可以将值从打开的 ThirdFragment 传递到前一个 SecondFragment 与新的导航组件? (当 ThirdFragment 完成时)

我知道 onActivityResult,但如果 Nav.Component 提供的解决方案比我想要的更好。

谢谢!

【问题讨论】:

    标签: android android-fragments android-architecture-navigation


    【解决方案1】:

    这个答案有点晚了,但有人可能会觉得它很有用。在导航组件库的更新版本中,现在可以在导航返回时传递数据。

    假设栈是这样的

    片段A --> 片段B。

    我们现在在FragmentB,当我们回到FragmentA时我们想传递数据。

    FragmentA里面我们可以用key创建一个观察者:

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val navController = findNavController()
    // Instead of String any types of data can be used
    navController.currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")
        ?.observe(viewLifecycleOwner) { 
    
        }
    }
    

    然后在FragmentB 内部,如果我们通过访问先前的返回堆栈条目来更改其值,它将被传播到FragmentA 并通知观察者。

    val navController = findNavController()
    navController.previousBackStackEntry?.savedStateHandle?.set("key", "value that needs to be passed")
    navController.popBackStack()
    

    【讨论】:

    【解决方案2】:

    刚刚遇到setFragmentResult(),非常好用。这方面的文档是here

    如果您正在导航:片段 A -> 片段 B -> 片段 A 将此添加到片段 A:

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setFragmentResultListener("requestKey") { requestKey, bundle ->
            shouldUpdate = bundle.getBoolean("bundleKey")
        }
    }
    

    然后在片段B中添加这行代码:

    setFragmentResult("requestKey", bundleOf("bundleKey" to "value to pass back"))
    // navigate back toFragment A
    

    当您导航回片段 A 时,侦听器将触发,您将能够获取捆绑包中的数据。

    【讨论】:

    • 这非常有效,在我看来更清晰!
    【解决方案3】:

    您要求的是反模式。你应该要么

    • 使用您要设置的新值再次导航到第二个片段

    • 在单独的活动中使用第三个片段并以startActivityForResult()开始它

    • 使用 ViewModel 或某种单例模式来保留数据(确保在不再需要数据后清除数据)

    这些是我想到的一些模式。希望对您有所帮助。

    【讨论】:

    • 在某些情况下,您的解决方案不起作用。就我而言,有一个片段应该将结果返回到它的前一个片段,而前一个片段可能每次都不同。就像 startActivityForResult
    • “你要求的是反模式。”定义反模式。我发现使用 ViewModel 进行转换是一种反模式。为什么一个活动以结果结束不是反模式,而是以结果结束一个片段是反模式?
    • @funct7 有什么解决办法吗?
    • 解决方案在这里 - github.com/PHELAT/NavigationResult 现在您可以将数据发送回之前的片段。它只是 - startActivityForResult 但用于片段! (Jetpack 导航组件的插件)。
    • > 在单独的活动中使用第三个片段。那不应该是单活动应用程序吗?
    【解决方案4】:

    作为described here:

    使用操作进行导航时,您可以选择从返回堆栈中弹出其他目的地。例如,如果您的应用程序具有初始登录流程,则一旦用户登录,您应该将所有与登录相关的目的地从后台堆栈中弹出,以便“后退”按钮不会将用户带回登录流程。

    要在从一个目的地导航到另一个目的地时弹出目的地,请将 app:popUpTo 属性添加到关联元素。 app:popUpTo 告诉 Navigation 库从 back stack 中弹出一些目的地,作为调用 navigate() 的一部分。属性值是应保留在堆栈中的最新目的地的 ID。

    <fragment
        android:id="@+id/c"
        android:name="com.example.myapplication.C"
        android:label="fragment_c"
        tools:layout="@layout/fragment_c">
    
        <action
            android:id="@+id/action_c_to_a"
            app:destination="@id/a"
            app:popUpTo="@+id/a"
            app:popUpToInclusive="true"/>
    </fragment>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-12-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-22
      相关资源
      最近更新 更多