导航架构组件 - 将参数数据传递给 startDestination
Navigation Architecture Component- Passing argument data to the startDestination
我有一个 activity A 开始 activity B 传递给它一些意图数据。 Activity B 托管来自新导航架构的导航图 Component.I 想要将该意图数据作为参数传递给 startDestination 片段如何做到这一点?
TLDR:您必须手动膨胀图形,将 keys/values 添加到 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
好的,感谢 Google 团队的 Ian Lake,我找到了解决该问题的方法。
假设你有一个 activity A 将以一些意图数据开始 activity B 并且你想在 startDestination 中获取该数据如果你使用安全参数,你有两个选择这里是我的情况你可以做
StartFragmentArgs.fromBundle(requireActivity().intent?.extras)
从 Intent 中读取参数。如果你不使用安全参数,你可以从你自己使用的包中提取数据 requireActivity().intent?.extras
这将 return 一个你可以使用的包而不是片段 getArguments()
方法。就这样我试了一下,一切正常。
所以对于仍在为此苦苦挣扎的人们。我找到了另一种不使用 Safe-Args 的方法和使用@Elliot 的答案的步骤。
所以假设你在 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
它已在 1.0.0-alpha07
中修复。 See detail.
解决方案与 Elliot Schrock 的答案类似,但由官方包装 API。
我们必须手动充气 NavHostFragment
或 graph
使用
NavHostFragment.create(R.navigation.graph, args)
或
navController.setGraph(R.navigation.graph, args)
args 是我们要传递到起始目的地的数据。
我认为这在 1.0.0 版本中又发生了变化。而Google在官方文档中已经很好的隐藏了这些信息。或者至少我很难找到它,但在 迁移到导航组件 指南中偶然发现了它。这里提到了如何将参数传递给起始目的地:Pass activity destination args to a start destination fragment
简而言之
- 您必须以编程方式设置导航图:
findNavController(R.id.main_content)
.setGraph(R.navigation.product_detail_graph, intent.extras)
- 不要在 NavHostFragment XML 声明中设置图表。
- 从接收方读取附加信息:
val args by navArgs<ProductDetailsArgs>()
val productId = args.productId
更新:Google 表示确实缺少将参数传递给初始导航目标的官方文档。希望这会尽快添加为导航组件文档的一部分。
最后,我找到了解决这个问题的方法。
在写这个答案时,我正在使用 Navigation 2.2.0-alpha01
如果您想将一些数据作为参数直接从主机 activity 传递到起始目的地,您需要在主机 activity 的 onCreate() 方法中手动设置主机的导航图,如下图:
获取导航控制器:
val navController by lazy { findNavController(R.id.<your_nav_host_id>) }
然后在主机activity的onCreate()
val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)
或者,如果您想将整个 intent extras 原样传递给 startDestination:
navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)
因为 intent.extras
只会 return 一个 Bundle
When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in
the NavHostFragment definition, because doing so results in inflating
and setting the navigation graph twice.
在您的 startDestination 片段中阅读这些参数时:
如果您使用的是 Safe Args Plugin(非常推荐),那么在您的片段中:
private val args by navArgs<DummyFragmentArgs>()
Safe Args 插件会通过将 Args 附加到您的片段名称来生成 Args class。例如,如果您的片段名为 DummyFragment
,那么 Safe Args 将生成一个名为 DummyFragmentArgs
的 class
其中 navArgs<>
是 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
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
阅读解决方案后,我做了一个适合我需要的解决方案,
此解决方案假设发送到托管此图
的 activity 的数据
起始目的地:
@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);
}
以下来自官方文档的 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())
然后在片段中您可以检索参数为:
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>
您可以将数据传递到应用程序的起始目的地。首先,您必须显式构造一个 Bundle 来保存数据。接下来,使用以下方法之一将 Bundle 传递到起始目的地
您可以从代码中手动设置图形并为其添加参数并从 xml 中删除 app:navGraph
并在 activity
中使用这行代码
navController.setGraph(R.navigation.graph, args)
我使用了 Elliot Schrock 的回答,但以不同的方法添加了包
navController.setGraph(R.navigation.nav_graph, intent.extras!!)
我有一个 activity A 开始 activity B 传递给它一些意图数据。 Activity B 托管来自新导航架构的导航图 Component.I 想要将该意图数据作为参数传递给 startDestination 片段如何做到这一点?
TLDR:您必须手动膨胀图形,将 keys/values 添加到 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
好的,感谢 Google 团队的 Ian Lake,我找到了解决该问题的方法。 假设你有一个 activity A 将以一些意图数据开始 activity B 并且你想在 startDestination 中获取该数据如果你使用安全参数,你有两个选择这里是我的情况你可以做
StartFragmentArgs.fromBundle(requireActivity().intent?.extras)
从 Intent 中读取参数。如果你不使用安全参数,你可以从你自己使用的包中提取数据 requireActivity().intent?.extras
这将 return 一个你可以使用的包而不是片段 getArguments()
方法。就这样我试了一下,一切正常。
所以对于仍在为此苦苦挣扎的人们。我找到了另一种不使用 Safe-Args 的方法和使用@Elliot 的答案的步骤。
所以假设你在 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
它已在 1.0.0-alpha07
中修复。 See detail.
解决方案与 Elliot Schrock 的答案类似,但由官方包装 API。
我们必须手动充气 NavHostFragment
或 graph
使用
NavHostFragment.create(R.navigation.graph, args)
或
navController.setGraph(R.navigation.graph, args)
args 是我们要传递到起始目的地的数据。
我认为这在 1.0.0 版本中又发生了变化。而Google在官方文档中已经很好的隐藏了这些信息。或者至少我很难找到它,但在 迁移到导航组件 指南中偶然发现了它。这里提到了如何将参数传递给起始目的地:Pass activity destination args to a start destination fragment
简而言之
- 您必须以编程方式设置导航图:
findNavController(R.id.main_content)
.setGraph(R.navigation.product_detail_graph, intent.extras)
- 不要在 NavHostFragment XML 声明中设置图表。
- 从接收方读取附加信息:
val args by navArgs<ProductDetailsArgs>()
val productId = args.productId
更新:Google 表示确实缺少将参数传递给初始导航目标的官方文档。希望这会尽快添加为导航组件文档的一部分。
最后,我找到了解决这个问题的方法。
在写这个答案时,我正在使用 Navigation 2.2.0-alpha01
如果您想将一些数据作为参数直接从主机 activity 传递到起始目的地,您需要在主机 activity 的 onCreate() 方法中手动设置主机的导航图,如下图:
获取导航控制器:
val navController by lazy { findNavController(R.id.<your_nav_host_id>) }
然后在主机activity的onCreate()
val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)
或者,如果您想将整个 intent extras 原样传递给 startDestination:
navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)
因为 intent.extras
只会 return 一个 Bundle
When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in the NavHostFragment definition, because doing so results in inflating and setting the navigation graph twice.
在您的 startDestination 片段中阅读这些参数时:
如果您使用的是 Safe Args Plugin(非常推荐),那么在您的片段中:
private val args by navArgs<DummyFragmentArgs>()
Safe Args 插件会通过将 Args 附加到您的片段名称来生成 Args class。例如,如果您的片段名为 DummyFragment
,那么 Safe Args 将生成一个名为 DummyFragmentArgs
其中 navArgs<>
是 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
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
阅读解决方案后,我做了一个适合我需要的解决方案, 此解决方案假设发送到托管此图
的 activity 的数据起始目的地:
@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);
}
以下来自官方文档的 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())
然后在片段中您可以检索参数为:
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>
您可以将数据传递到应用程序的起始目的地。首先,您必须显式构造一个 Bundle 来保存数据。接下来,使用以下方法之一将 Bundle 传递到起始目的地
您可以从代码中手动设置图形并为其添加参数并从 xml 中删除 app:navGraph
并在 activity
navController.setGraph(R.navigation.graph, args)
我使用了 Elliot Schrock 的回答,但以不同的方法添加了包
navController.setGraph(R.navigation.nav_graph, intent.extras!!)