导航架构组件 - 将参数数据传递给startDestination

时间:2018-05-14 15:59:20

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

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

9 个答案:

答案 0 :(得分:16)

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

第1步

该文档告诉您在<fragment>布局的Activity标记中设置图表。类似的东西:

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

删除设置graph=

的行

第2步

在将显示NavHostFragment的活动中,像这样夸大图表:

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 :(得分:9)

下面是官方文档中的Pass data to the start destination部分:

首先,构造一个包含数据的捆绑包:

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>

答案 2 :(得分:8)

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

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

我们必须手动为NavHostFragmentgraph充气

使用

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

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

参数是我们要传递到起始目标的数据。

答案 3 :(得分:6)

好的,感谢Google团队的Ian Lake,我找到了解决这个问题的方法。 假设您有一个活动A,它将使用一些意图数据启动活动B,并且您希望在startDestination中获取该数据,如果您使用安全参数,那么您可以在这里使用两个选项

class SomePlugin { public __construct() { add_action('wp_head', array(&$this, 'addMetatags')); } public function addMetatags() { echo '<meta property="og:type" content="article" '; } }

从Intent中读取args。如果你不使用安全args,你可以从你自己使用的StartFragmentArgs.fromBundle(requireActivity().intent?.extras)包中提取数据,这将返回你可以使用的Bundle而不是片段requireActivity().intent?.extras方法。这就是我尝试它,一切正常。

答案 4 :(得分:2)

我认为1.0.0版本再次改变了这一点。 Google在官方文档中很好地隐藏了这些信息。或者至少我很难找到它,但是在迁移到导航组件指南中偶然发现了它。这里提到了如何将参数传递给起始目的地:

https://developer.android.com/guide/navigation/navigation-migrate#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

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

答案 5 :(得分:1)

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

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

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

让您获得navController:

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,那么安全Args会生成一个名为DummyFragmentArgs

的类

其中navArgs<>Android KTX中定义的扩展功能

如果您未使用Android KTX,则可以获取args对象,例如:

val args = DummyFragmentArgs.fromBundle(arguments!!)

一旦获取了arguments对象,就可以简单地获取参数:

args.someArgument

请注意我们如何传递"some_argument"作为参数,并使用安全参数将其读为someArgument

如果您不使用安全Args(虽然没有理由不使用它),则可以这样访问参数:

arguments?.getString("some_argument")

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

答案 6 :(得分:0)

因此,对于仍在为此奋斗的人民。我找到了另一种无需使用Safe-Args的方法,也可以使用@Elliot的答案。

因此,可以说您在活动B中从活动A接收了一些参数,并且您的活动B具有片段startDestination,您正在像这样初始化Nav控制器:

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

从Nav Controller中,您可以访问以XML设置的图形,如下所示,您可以在defaultArguments中设置参数:

navController.getGraph().addDefaultArguments(extras);

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

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

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

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

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

在阅读解决方案后,我做出了适合自己需求的解决方案, 此解决方案假定发送到托管此图的活动的数据

在开始目的地:

@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);
}