【问题标题】:Android Navigation Component : Pass value (arguments) in fragmentsAndroid导航组件:在片段中传递值(参数)
【发布时间】:2019-12-23 08:35:26
【问题描述】:

我做了什么:

我创建了 Navigation Drawer Activity,作为 Navigation Drawer Activity 的更新新格式,根据新的 Android 架构,我使用 Navigation Component 结构。

带有NavControllerNavigationUINavigationView 代码在下方当我点击任何导航项时打开片段。

    DrawerLayout drawer = findViewById(R.id.drawer_layout);
    NavigationView navigationView = findViewById(R.id.nav_view);
    // Passing each menu ID as a set of Ids because each
    // menu should be considered as top level destinations.
    mAppBarConfiguration = new AppBarConfiguration.Builder(
            R.id.nav_home, R.id.nav_profile, R.id.nav_privacy_policy,
            R.id.nav_terms, R.id.nav_contact_us, R.id.nav_share, R.id.nav_send)
            .setDrawerLayout(drawer)
            .build();
    NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
    NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
    NavigationUI.setupWithNavController(navigationView, navController);

这是给nav_host_fragment的:

<fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/mobile_navigation" />

使用这个navigation/mobile_navigation.xml进行导航

<?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/mobile_navigation"
    app:startDestination="@+id/nav_home">

    <fragment
        android:id="@+id/nav_home"
        android:name="com.sohamerp.marsremedies.fragment.HomeFragment"
        android:label="@string/menu_home"
        tools:layout="@layout/fragment_home" />

    <fragment
        android:id="@+id/nav_profile"
        android:name="com.sohamerp.marsremedies.fragment.ProfileFragment"
        android:label="@string/menu_my_profile"
        tools:layout="@layout/fragment_profile" />

    <fragment
        android:id="@+id/nav_privacy_policy"
        android:name="com.sohamerp.marsremedies.fragment.PrivacyPolicyFragment"
        android:label="@string/menu_privacy_policy"
        tools:layout="@layout/fragment_privacy_policy" />

    <fragment
        android:id="@+id/nav_terms"
        android:name="com.sohamerp.marsremedies.fragment.TermsConditionFragment"
        android:label="@string/menu_terms"
        tools:layout="@layout/fragment_terms_condition" />

    <fragment
        android:id="@+id/nav_contact_us"
        android:name="com.sohamerp.marsremedies.fragment.ContactUsFragment"
        android:label="@string/menu_contact_us"
        tools:layout="@layout/fragment_terms_condition" />

</navigation>

我想做什么:

现在我想在 Fragment 被调用时将一些值作为包(参数)传递。

场景:我有两个片段PrivacyPolicyFragmentTermsConditionsFragment,在这两个片段中,我只是在 WebView 中相应地打开链接。所以当我点击Privacy Policy的菜单项时,我会传递一个与之相关的链接。

在这个新结构 navigation/mobile_navigation.xml 打开片段中,我如何传递参数?

有什么帮助吗?

【问题讨论】:

标签: android android-fragments android-architecture-navigation


【解决方案1】:

所以我忘了通过这个链接:Define Destination Arguments

但是这个答案对所有像我这样的懒人都有帮助:

在项目级别添加依赖build.gradle

classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0"

在应用级别应用插件build.gradle

apply plugin: "androidx.navigation.safeargs"

使用 XML:预定义(静态)值:

在导航的xml文件/navigation/mobile_navigation.xml中声明argument标签如下或者你可以通过this link设计:

<fragment
    android:id="@+id/nav_privacy_policy"
    android:name="com.sohamerp.marsremedies.fragment.PrivacyPolicyFragment"
    android:label="@string/menu_privacy_policy"
    tools:layout="@layout/fragment_privacy_policy" >
    <argument
        android:name="privacyPolicyLink"
        app:argType="string"
        android:defaultValue="http://sohamerp.com/avo/avo_privacy_policy.html"/>
</fragment>

<fragment
    android:id="@+id/nav_terms"
    android:name="com.sohamerp.marsremedies.fragment.PrivacyPolicyFragment"
    android:label="@string/menu_terms"
    tools:layout="@layout/fragment_terms_condition" >
    <argument
        android:name="privacyPolicyLink"
        app:argType="string"
        android:defaultValue="http://sohamerp.com/avo/avo_privacy_policy.html"/>
</fragment>

现在您必须在 Fragment 中编写代码,例如:

if(getArguments() != null) {
    // The getPrivacyPolicyLink() method will be created automatically.
    String url = PrivacyPolicyFragmentArgs.fromBundle(getArguments()).getPrivacyPolicyLink();
}

希望它能帮助你其他人。

【讨论】:

  • 或者,要生成适合 Kotlin-only 模块的 Kotlin 代码,请添加:apply plugin: "androidx.navigation.safeargs.kotlin"
  • 我们可以使用bundle来传递数据吗?
  • 如何传递数据?喜欢从这里:Navigation.findNavController(view).navigate(R.id.action);
  • @sohin 来自文档:“强烈建议使用安全参数来导航和传递数据,因为它可以确保类型安全。在某些情况下,例如,如果您不使用 Gradle,则不能使用 Safe Args 插件。在这些情况下,您可以使用 Bundles 直接传递数据。"
【解决方案2】:

要将参数传递给其他片段/目的地,请使用Safe Args,以确保类型安全。就像@bromden 所说明的那样,Safe Args 将为 action 起源的每个片段/目标生成一个类。然后,您可以将参数传递到导航到片段的action

在接收片段中,如果您的代码在 Kotlin 中,请说 PrivacyFragment,请使用 navArgs() 属性委托来访问参数。即

val args: PrivacyFragmentArgs by navArgs()

为了更好地理解这一点,请访问Pass data between destinations

【讨论】:

    【解决方案3】:

    在这种情况下,您可以使用

      private NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
      // Create the Bundle to pass, you can put String, Integer, or serializable object
      Bundle bundle = new Bundle();
      bundle.putString("link","http://yourlink.com/policy");
      bundle.putSerializable("USER", user); // Serializable Object
      navController.navigate(R.id.nav_terms, bundle); // called fragment with agruments
    

    如果有任何帮助,您可以回复它

    【讨论】:

    • 如何获取 R.id.nav_terms 中的捆绑包?
    • 在下一个片段中,在 onCreateView 中,调用 Bundle arguments = getArguments();如果(参数!= null){}
    • 在 Kotlin 中 requireArguments() 如果没有 Bundle 会抛出 IllegalStateException,我不得不使用 catch 块
    • 除了@Vivek Handle 响应之外,在 if 子句中您必须执行类似 arguments.get("KEY_ID") 的操作。示例: if (arguments != null) { user = (User) arguments.get("User"); }
    【解决方案4】:

    你可以实现NavigationView.OnNavigationItemSelectedListener 并做这样的事情:

     override fun onNavigationItemSelected(item: MenuItem): Boolean {
       drawer_layout.closeDrawers()
    
            if (item.itemId == nv_navigation_drawer_navigation_view.checkedItem?.itemId)
                return false
    
         Handler().postDelayed({
                    when (item.itemId) {
                        R.id.nav_privacy_policy -> {
                               val action = FragmentDirections.actionFragmentToPrivacyFragment("Policy link")
    
                         findNavController().navigate(action)
    
                        }
                    }
                }, DRAWER_NAVIGATION_DELAY)
      return true
        }
    

    在 xml 中,您可以向接收片段添加参数,在这种情况下

       <fragment
        android:id="@+id/nav_privacy_policy"
        android:name=".fragment.PrivacyPolicyFragment"
        android:label="@string/menu_privacy_policy"
        tools:layout="@layout/fragment_privacy_policy">
    
        <argument
            android:name="policy"
            app:argType="string" />
    </fragment>
    

    【讨论】:

    【解决方案5】:

    简单快速的解决方案:

    在目的地之间传递参数

    Bundle bundle = new Bundle();
    bundle.putString("amount", amount);
    Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);
    

    和接收

    TextView tv = view.findViewById(R.id.textViewAmount);
    tv.setText(getArguments().getString("amount"));
    

    【讨论】:

      【解决方案6】:

      您还可以传递可序列化的对象、枚举值和原始类型的数组。 例如:

      enum class ObjectType : Serializable {
          FIRST, SECOND
      }
      

      然后,向 xml 添加参数

      <fragment
              android:id="@+id/nav_profile"
              android:name="com.sohamerp.marsremedies.fragment.ProfileFragment"
              android:label="@string/menu_my_profile"
              tools:layout="@layout/fragment_profile" >
      
              <argument
                  android:name="myObjectType"
                  android:defaultValue="SECOND"
                  app:argType="com.project.app.data.ObjectType" />
      </fragment>
      

      注意,您应该指定完整的路径!

      【讨论】:

        【解决方案7】:

        在 Android Studio 3.2+ 的新版本中,需要在 build.gradle 文件中添加以下依赖和插件

        第一步

        Project-Level中添加依赖 build.gradle

        dependencies {
            classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.3.5'
        }
        

        App-Level中应用plugins build.gradle

        plugins {
            id 'androidx.navigation.safeargs' 
        }
        

        第二步

        1. 在导航文件中,res/navigation/nav_graph.xml
        2. 在任何 fragment 或带有 action 标签的内部片段中声明 argument 标签
        3. 列表项

        示例 xml 代码

         <fragment
             android:id="@+id/nav_register"
             android:name="com.pd.demo.ui.profile.RegisterFragment"
             android:label="@string/title_register"
             tools:layout="@layout/fragment_register">
             <action
                 android:id="@+id/action_nav_register_to_nav_verify_otp"
                 app:destination="@id/nav_verify_otp">
                 <argument
                     android:name="mobile"
                     app:argType="string" />
                 <argument
                     android:name="password"
                     app:argType="string" />
             </action>
         </fragment>
        

        第三步

        在 Kotlin 代码下方,将参数传递给目标片段

        val bundle = bundleOf("mobile" to binding.etMobileNo.text.toString().trim())
        Navigation.findNavController(binding.root).navigate(R.id.action_nav_register_to_nav_verify_otp, bundle)
        

        第四步

        在 Kotlin 代码下方,从源代码片段获取 bundle 参数

        override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)
            mobileNo = arguments!!.getString("mobile").toString()
            password = arguments!!.getString("password").toString()
        }
        

        这段代码会有所帮助

        【讨论】:

          【解决方案8】:

          我遇到了同样的问题,但我仍然无法使用片段方向传递参数。由于我需要几个片段中的值,我决定在我的主要活动中使用一个伴随对象。它可能不是最好的,但它解决了问题: 类 MainActivity : AppCompatActivity() {

              companion object{
                  var myGlobalVar = "Example"
              }
          
          override fun onCreate(savedInstanceState: Bundle?) {.... 
          

          然后我可以通过导入它来访问我所有片段中的值:

          import myAppPackage.MainActivity.Companion.myGlobalVar
          

          我不得不从我的 navGraph 中删除参数,但我仍然可以在后台访问它。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2019-06-02
            • 1970-01-01
            • 1970-01-01
            • 2020-04-19
            • 2021-12-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多