Android 导航架构组件:如何将捆绑数据传递给 startDestination

Posted

技术标签:

【中文标题】Android 导航架构组件:如何将捆绑数据传递给 startDestination【英文标题】:Android Navigation Architecture Component: How to pass bundle data to startDestination 【发布时间】:2019-05-23 15:06:53 【问题描述】:

我有一个包含NavHostFragment 的活动。活动在其意图中接收某些值。我想将此数据传递给导航图的第一个片段,即startDestination。我找不到任何有关此的文档。

我已经经历了this question on SO,但我似乎找不到navController.getGraph()addDefaultArguments 方法。

是否可以将捆绑包传递给startDestination

【问题讨论】:

我刚刚签入1.0.0-alpha071.0.0-alpha08,我们有addDefaultArguments(),它在Java 和kotlin 中都可以正常工作。但是对于1.0.0-alpha09,他们已经删除了addDefaultArguments(),这可能是暂时的,应该尽快修复。所以现在你可以使用1.0.0-alpha08 @Anmol,是的,情况似乎如此。我不明白在 1.0.0-alpha09 中删除 addDefaultArguments() 的原因。目前,我已恢复到 1.0.0-alpha08。 ***.com/q/53928500/7972699 如果您有任何想法,请在此处回复 @Anmol 我已根据最新的导航文档添加了答案。 ***.com/a/57607441/3036824 【参考方案1】:

当我在更新的导航文档中找到正确的方法时回答我自己的问题。

在撰写此答案时,我使用的是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

【讨论】:

【参考方案2】:

我也遇到了同样的问题,

我就是这样解决的:

    your_activity.xml 删除 NavHostFragment 的 xml 设置:即删除 app:navGraph="@navigation/nav_graph

这就是你的 XML 的样子。

        <fragment
        android:id="@+id/nav_host"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_
        android:layout_
        app:defaultNavHost="true"
        />

    添加 NavHostFragment 的设置以编程方式在活动的onCreate() 中。 并使用NavGraph.addDefaultArguments(bundleData) api

    传递捆绑数据
        override fun onCreate(savedInstanceState: Bundle?) 
            super.onCreate(savedInstanceState)
            setContentView(R.layout.editor_layout)
            setupNavigation()
        
    
        private fun setupNavigation() 
            val navHostFragment = nav_host as NavHostFragment
            val navController = navHostFragment.navController
            val navInflater = navController.navInflater
            val graph = navInflater.inflate(R.navigation.nav_graph)
            graph.addDefaultArguments(intent!!.extras!!) // This is where you pass the bundle data from Activity to StartDestination 
            navHostFragment.navController.graph = graph
        
    

更新:

我的项目 Gradle 文件中的依赖项:

dependencies 

    def nav_version = "1.0.0-alpha08"

    implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
    implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin

注意:在导航组件版本 1.0.0-alpha09 中,由于某种原因,谷歌没有方法,因为 addDefaultArguments() 可能很快就会修复。但较低版本的有addDefaultArguments() 方法。我在java 和kotlin 中都检查过,所以尝试使用1.0.0-alpha071.0.0-alpha08

【讨论】:

我正在尝试在 Java 中执行此操作。我按照你的步骤,问题是graph.addDefaultArguments,没有这样的方法叫做addDefaultArguments @PraveenSingh 检查您是否能够在项目中导入 NavDestination 类 Ref: developer.android.com/reference/kotlin/androidx/navigation/…【参考方案3】:

经过一番研究,我找到了解决方案。它适用于最新的导航库版本。参考以下代码:

    将此添加到您的活动布局中。注意:我们没有在 xml 文件中设置 app:navGraph 参数。我们将动态设置它。

    <fragment
        android:id="@+id/fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_
        android:layout_
        android:layout_weight="1"
        app:defaultNavHost="true" />
    

    在您的活动 java 文件中,编写以下代码并进行相应的更改。使用 NavArgument 传递您的参数值并将参数添加到您的自定义 Navgraph,然后设置图表。

    public class YourActivity extends AppCompatActivity 
         private NavArgument nameArg, mailArg;
    
         @Override
         protected void onCreate(Bundle savedInstanceState) 
            super.onCreate(savedInstanceState);
            setContentView(R.layout.profile);
            nameArg = new NavArgument.Builder().setDefaultValue("your name").build();
            mailArg = new NavArgument.Builder().setDefaultValue("your email id").build();
            NavController navController = Navigation.findNavController(this, R.id.fragment);
            NavInflater navInflater = navController.getNavInflater();
            NavGraph navGraph = navInflater.inflate(R.navigation.nav_profile_graph);
            navGraph.addArgument("your name key", nameArg);
            navGraph.addArgument("your mail key", mailArg);
            navController.setGraph(navGraph);
        
    
    

    编写下面的导航图并将相同的参数键添加到起始片段。

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:android="http://schemas.android.com/apk/res/android"
       xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools"
       android:id="@+id/nav_graph"
       app:startDestination="@+id/profile_basic">
    
       <fragment
          android:id="@+id/profile_basic"
          android:name="com.yourpackage.ProfileBasicFragment"
          android:label="Profile Basic"
          tools:layout="@layout/fragment_profile_basic">
    
          <argument android:name="your name key"
              app:argType="string"/>
    
          <argument android:name="your mail key"
              app:argType="string"/>
    
       </fragment>
    </navigation>
    

    在您的片段中,只需使用 getArguments() 函数获取值。

    String name = getArguments().getString("your name key");
    String mail = getArguments().getString("your mail key");
    

【讨论】:

【参考方案4】:

虽然这是一个较晚的答案,但有一种非常简单的方法可以使用导航控制器/导航架构传递包:

将发送数据的片段

//Best to put in onViewCreated
val navController = findNavController()

//Put in code where you want to start navigation
val b = Bundle()
b.putString("key_1", "Data 1")
b.putString("key_2", "Data 2")

navController.navigate(R.id.action_signupFragment_to_signinFragment,b)

将接收数据的片段

val data_1: String = arguments?.getString("key_1")?:""
val data_1: String = arguments?.getString("key_2")?:"" 

根据您发送的数据类型,您需要更新安全调用或使变量可为空。

【讨论】:

【参考方案5】:

我也找不到这种方法。它在架构组件文档中不存在。

但这是将参数设置为起始目的地的另一种方法:

// Kotlin Code, in Fragment
with(findNavController().graph) 
    get(startDestination).addArgument(...)

【讨论】:

developer.android.com/reference/kotlin/androidx/navigation/… 哦,那是 Kotlin 文档,我刚刚看过标准 (Java) 文档...但奇怪的是 java 和 kotlin api 不提供相同的功能。 这似乎是一个有趣的问题要解决。我认为 googler 错过了一个大用例,这很奇怪 我刚刚签入 1.0.0-alpha07 我们有 addDefaultArguments() 并且它在 Java 和 kotlin @the_dani 中都可以正常工作 所以他们在 java api 的 alpha09 中删除了它?【参考方案6】:

我检查了源代码,发现导航目的地和参数有很多变化。 我认为将参数传递给起始目的地的正确方法是使用“addArgument”方法,如下所示:

val argument1 = 1 //First value
val argument2 = "Value" //Second value
val navArgument1=NavArgument.Builder().setDefaultValue(argument1).build()
val navArgument2=NavArgument.Builder().setDefaultValue(argument2).build()
navController.getGraph().addArgument("Key1",navArgument1)
navController.getGraph().addArgument("Key2",navArgument2)

也许有更好的方法,但我没有找到。

【讨论】:

【参考方案7】:
class MainActivity : BaseActivity()  

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment = container as NavHostFragment
        val inflater = navHostFragment.navController.navInflater
        val graph = inflater.inflate(R.navigation.main_nav)

        var data : Data  = intent.getParcelableExtra("DATA") as Data
        var bundle : Bundle = Bundle()
        bundle.putParcelable("DATA", data)
        graph.addDefaultArguments(bundle)
        graph.addDefaultArguments(intent!!.extras!!)
        navHostFragment.navController.graph = graph

    

在Activity中添加以上代码,使用导航发送数据

override fun onActivityCreated(savedInstanceState: Bundle?) 
        super.onActivityCreated(savedInstanceState)

        var data = NavHostFragment.findNavController(this).graph.defaultArguments.getParcelable("DATA") as Booking


在片段端添加以上代码

【讨论】:

【参考方案8】:

您可以像这样在图表中添加参数

<fragment
  android:id="@+id/exampleFragment"
  android:label="example_fragment"
  android:name="com.example.yourapp.ui.ExampleFragment"
  tools:layout="@layout/example_fragment">
<argument
  android:name="exampleArgs"
  app:argType="reference"
  android:defaultValue="@string/example"/>
</fragment>

https://developer.android.com/guide/navigation/navigation-pass-data

【讨论】:

【参考方案9】:

导航 1.0.0

        val navHostFragment = root_nav_host_fragment as NavHostFragment
        val navController = navHostFragment.navController
        val navInflater = navController.navInflater
        val graph = navInflater.inflate(R.navigation.navigation)
        val sectionId = intent.getIntExtra(KEY_SECTION_ID, -1)
        val bundle = bundleOf(KEY_SECTION_ID to sectionId)
        navHostFragment.navController.setGraph(graph, bundle)

【讨论】:

以上是关于Android 导航架构组件:如何将捆绑数据传递给 startDestination的主要内容,如果未能解决你的问题,请参考以下文章

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

如何在将数据推送到导航堆栈之前将数据传递给视图控制器并加载它?

如何正确地将数据传递给以前的 viewController(有导航)?

Angular 2:将数据传递给路由?

如何将 ajax 数据传递给 React 组件?

如何将可编辑数据传递给组件?