【问题标题】:Navigation Architecture Component- Passing argument data to the startDestination导航架构组件 - 将参数数据传递给 startDestination
【发布时间】:2018-10-24 08:43:33
【问题描述】:

我有一个活动 A,它启动活动 B,向它传递一些意图数据。活动 B 托管来自新导航架构组件的导航图。我想将该意图数据作为参数传递给 startDestination 片段,该怎么做?

【问题讨论】:

  • 我很确定导航编辑器有“参数”选项,然后你可以添加 safe-args gradle 插件,但细节对我来说有点模糊
  • 是的,我知道,但没有办法将参数传递给起始目标片段

标签: android navigation android-architecture-components android-architecture-navigation


【解决方案1】:

TLDR:您必须手动扩充图表,将键/值添加到 defaultArgs,然后在 navController 上设置图表。

第 1 步

文档告诉您在Activity 布局中的<fragment> 标记中设置图形。比如:

<fragment
    android:id="@+id/navFragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    app:graph="@navigation/nav_whatever"
    app:defaultNavHost="true"
    />

删除设置graph=的行。

第 2 步

在将显示您的 NavHostFragment 的 Activity 中,像这样放大图表:

val navHostFragment = navFragment as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.nav_whatever)

navFragment 是您在 XML 中为片段提供的 id,如上所述。

第 3 步 [关键!]

创建一个包来保存您要传递给startDestination 片段的参数并将其添加到图表的默认参数中:

val bundle = Bundle()
// ...add keys and values
graph.addDefaultArguments(bundle)

第 4 步

在宿主的navController上设置图表:

navHostFragment.navController.graph = graph

【讨论】:

  • 您的解决方案会起作用,但相当复杂,我找到了更好的方法,但在另一个答案中
  • 此解决方案在 1.0.0-alpha09 中不再有效。 addDefaultArgument 函数已被删除。
  • addDefaultArgument 已从导航架构组件中删除。请看下面我的回答,看看官方推荐的方法。
【解决方案2】:

好的,感谢 Google 团队的 Ian Lake,我找到了解决该问题的方法。 假设您有一个活动 A,它将使用一些意图数据启动活动 B,并且您想在 startDestination 中获取该数据,如果您使用安全 args,您有两个选择,这是我的情况,您可以这样做

StartFragmentArgs.fromBundle(requireActivity().intent?.extras)

从 Intent 中读取参数。如果您不使用安全参数,您可以从您自己使用的requireActivity().intent?.extras 的捆绑包中提取数据,这将返回一个您可以使用的捆绑包,而不是片段getArguments() 方法。就是这样,我试了一下,一切正常。

【讨论】:

  • StartFragmentArgs 类从何而来?它是否包含在导航拱依赖中?
  • 导航生成的类。如果您使用的是安全参数。例如,此处的片段称为 StartFragment,因此生成的 arg 类将是 StartFragmentArgs。如果片段名为 FooFragment 生成的类将是 FooFragmentArgs 等等
  • 我尝试使用它并在 Activity StartFragmentArgs.fromBundle(requireActivity().intent?.extras) 的 onCreate 中添加了这一行,但发送到我的 startDestination 的参数为空
  • 当您启动具有图表的活动时,您将数据作为意图传递并将其提取到requireActivity().intent?.extras
  • 您的回答不完整。当您使用 SafeArgs 设置捆绑包时,它会返回设置所有捆绑包参数的类对象本身。但是您没有告诉我们如何在片段中取回该捆绑包。如果我们使用 fromBundle 它总是会返回一个新对象,因此当您尝试获取它时它将不再具有该值,它将为 null
【解决方案3】:

已在1.0.0-alpha07 中修复。 See detail.

解决方案类似于 Elliot Schrock 的回答,但由官方 API 包装。

我们必须手动充气NavHostFragmentgraph

使用

NavHostFragment.create(R.navigation.graph, args)

或者

navController.setGraph(R.navigation.graph, args)

args 是我们要传递到起始目的地的数据。

【讨论】:

    【解决方案4】:

    我认为这在 1.0.0 版本中再次发生了变化。而谷歌在官方文档中已经很好地隐藏了这些信息。或者至少我很难找到它,但在迁移到导航组件指南中偶然发现了它。这里提到了如何将参数传递给起始目的地:Pass activity destination args to a start destination fragment

    总之

    1. 您必须以编程方式设置导航图:
    findNavController(R.id.main_content)
        .setGraph(R.navigation.product_detail_graph, intent.extras)
    
    1. 不要在 NavHostFragment XML 声明中设置图表。
    2. 从接收方读取附加信息:
    val args by navArgs<ProductDetailsArgs>()  
    val productId = args.productId
    

    更新:谷歌表示确实缺少将参数传递给初始导航目标的官方文档。希望这将作为导航组件文档的一部分尽快添加。

    【讨论】:

    • 嗨@Johan Paul 你能告诉我这里面的 R.id.main_content 是什么吗?
    • @rupesh 它是您通常在 XML 布局文件中指定导航图的 NavHostFragment 的 ID。
    【解决方案5】:

    以下来自官方文档的Pass data to the start destination 部分:

    首先,构造一个保存数据的Bundle:

    val bundle = Bundle().apply {
        putString(KEY, "value")
    }
    

    接下来,使用以下方法之一将 Bundle 传递到起始目的地:

    • 如果您以编程方式创建 NavHost

       NavHostFragment.create(R.navigation.graph, bundle)
      
    • 否则,您可以通过调用NavController.setGraph() 的以下重载之一来设置起始目标参数:

       navHostFragment.navController.setGraph(R.navigation.graph, bundle)
      

    那么您应该使用Fragment.getArguments() 来检索起始目的地中的数据。

    编辑:

    您也可以使用FragmentArgs 而不是手动创建捆绑包,这样更方便且输入安全:

    navHostFragment.navController.setGraph(R.navigation.graph, MyFragmentArgs(arg).toBundle())
    

    然后在片段中你可以检索 args 为:

    private val args: PodFragmentArgs by navArgs()
    

    确保您的片段在 navigation.xml 文件中有参数元素:

    <fragment
            android:id="@+id/myFragment"
            android:name="MyFragment"
            android:label="fragment_my"
            tools:layout="@layout/fragment_my">
            <argument
                android:name="argName"
                android:defaultValue="@null"
                app:argType="string"
                app:nullable="true" />
    </fragment>
    

    【讨论】:

    • 链接已损坏。如果您记得,请更新链接。
    • @PankajKumar 链接已更新,谢谢告知。
    【解决方案6】:

    所以最后,我找到了解决这个问题的方法。

    在撰写此答案时,我使用的是Navigation 2.2.0-alpha01

    如果你想直接将一些数据作为参数从宿主活动传递到起始目的地,你需要在宿主活动的 onCreate() 方法中手动设置宿主的导航图,如下所示:

    获取导航控制器:

    val navController by lazy { findNavController(R.id.<your_nav_host_id>) }
    

    然后在宿主活动的onCreate()

    val bundle = Bundle()
    bundle.putString("some_argument", "some_value")
    navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)
    

    或者,如果您想将整个意图附加内容原样传递给 startDestination:

    navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)
    

    因为intent.extras 只会返回Bundle

    当你使用 setGraph() 方法设置 navGraph 时,你应该避免设置 app:NavGraph 属性 NavHostFragment 定义,因为这样做会导致膨胀 并设置导航图两次。

    在您的 startDestination 片段中阅读这些参数时:

    如果您使用的是Safe Args Plugin(非常推荐),那么在您的片段中:

    private val args by navArgs<DummyFragmentArgs>()
    

    Safe Args 插件会通过将 Args 附加到您的片段名称来生成 Args 类。例如,如果您的片段名为DummyFragment,那么 Safe Args 将生成一个名为 DummyFragmentArgs 的类

    其中navArgs&lt;&gt;Android KTX中定义的扩展函数

    如果你没有使用 Android KTX,你可以像这样获取 args 对象:

    val args = DummyFragmentArgs.fromBundle(arguments!!)
    

    获得参数对象后,您可以简单地获取参数:

    args.someArgument
    

    请注意我们是如何将 "some_argument" 作为参数传递的,我们使用 Safe Args 将其读取为 someArgument

    如果您没有使用 Safe Args(但没有理由不使用它),您可以像这样访问您的参数:

    arguments?.getString("some_argument")
    

    所有这些都记录在此处的“迁移到导航组件”文档中: https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment

    【讨论】:

    • 你能用java给出这个解决方案吗?
    【解决方案7】:

    阅读解决方案后,我制作了一个适合我需要的解决方案, 此解决方案假定发送到托管此图表的活动的数据

    在起始目的地:

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        // work around get get starting destination with activity bundle
        userId = getActivity().getIntent().getIntExtra(KEY_USER_ID, -1);
    }
    

    【讨论】:

      【解决方案8】:

      addDefaultArguments 在最新版本的库中不再存在。我已经解决了这样的问题:

              val navHostFragment = fragment_navigation_onboarding as NavHostFragment
              val navController = navHostFragment.navController
              val navInflater = navController.navInflater
              val graph:NavGraph = navInflater.inflate(R.navigation.navigation_your_xml)
              val model = Model()//you might get it from another activity
              graph.addArgument("Data", NavArgument.Builder().setDefaultValue(model).build()) // This is where you pass the bundle data from Activity to StartDestination
              navHostFragment.navController.graph = graph
      

      【讨论】:

        【解决方案9】:

        所以对于仍在为此苦苦挣扎的人们。我找到了另一种不使用 Safe-Args 和使用@Elliot's Answer 的步骤的方法。

        假设您在 Activity B 中从 Activity A 收到了一些参数,并且您的 Activity B 有一个片段 startDestination 您正在像这样初始化 Nav 控制器:

        navController = Navigation.findNavController(this, R.id.detailFragment);
        

        从导航控制器您将可以访问您在 XML 中设置的图形,您可以在 defaultArguments 中设置参数:

        navController.getGraph().addDefaultArguments(extras);
        

        注意:如果键的值已经存在于图形 xml 中,这也会更新键的值

        现在在您的 Fragment 中,您必须像这样从 NavHostFragment 中找到默认参数:

        Bundle defaultArguments = NavHostFragment.findNavController(this).getGraph().getDefaultArguments();
        

        您将在那里获得价值。我不知道为什么@Elliot 认为这很关键,但应该是这样?

        更新 alpha09: 此版本不再支持 addDefault 参数,您必须使用 NavArgument

        【讨论】:

          【解决方案10】:

          您可以将数据传递到应用的起始目的地。首先,您必须显式构造一个包含数据的 Bundle。接下来,使用以下方法之一将 Bundle 传递到起始目的地 您可以从代码中手动设置图形并使用它添加参数并从 xml 中删除 app:navGraph 并在活动中使用这行代码

          navController.setGraph(R.navigation.graph, args)
          

          【讨论】:

            猜你喜欢
            • 2020-08-06
            • 2019-05-23
            • 1970-01-01
            • 2022-01-21
            • 1970-01-01
            • 2019-08-26
            • 2019-10-01
            • 1970-01-01
            • 2021-06-18
            相关资源
            最近更新 更多