繁体   English   中英

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

[英]Navigation Architecture Component- Passing argument data to the startDestination

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

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的活动中,像这样膨胀图表:

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)

第四步

在主机的navController上设置图形:

navHostFragment.navController.graph = graph

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

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

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

它已在1.0.0-alpha07 查看详情。

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

我们必须手动膨胀NavHostFragmentgraph

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

或者

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

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

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

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

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

以下将数据从官方文档传递到开始目的地部分:

首先,构造一个包含数据的 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>

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

在撰写此答案时,我正在使用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() 方法设置导航图时,应避免在 NavHostFragment 定义中设置 app:NavGraph 属性,因为这样做会导致导航图膨胀和设置两次。

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

如果您使用的是Safe Args 插件(非常推荐),则在您的片段中:

private val args by navArgs<DummyFragmentArgs>()

Safe Args 插件将通过将 Args 附加到您的片段名称来生成 Args 类。 例如,如果您的片段名为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

阅读解决方案后,我制作了一个适合我的需求的解决方案,该解决方案假定数据发送到承载此图的活动

在起始目的地:

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

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

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

因此,假设您从 Activity A 收到了 Activity B 中的一些参数,并且您的 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

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

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

我使用了 Elliot Schrock 的答案,但以不同的方法添加了捆绑包

navController.setGraph(R.navigation.nav_graph, intent.extras!!)
class HadithActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_hadith)
        val navHostFragment =
            supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
        val navController = navHostFragment.navController
        navController.setGraph(R.navigation.nav_hadith, intent.extras)
    }
}

activity_hadith.xml

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/fragmentContainerView"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_hadith" />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM