You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过Bottom Navigation View导航至带参数的Fragment

解决Bottom Navigation View导航带参数Fragment的异常问题

问题描述

我希望通过Bottom Navigation View从CrimeListFragment导航到CrimeDetailFragment,但CrimeDetailFragment要求传入UUID类型的crime_id参数。点击底部导航图标时触发异常,提示“必填参数crime_id缺失且无android:defaultValue”。不想硬编码默认值,希望在MainActivity中通过代码实现参数传递。

相关代码

MainActivity代码

package com.andpro.android.criminalintent

import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.onNavDestinationSelected
import androidx.navigation.ui.setupWithNavController
import com.google.android.material.bottomnavigation.BottomNavigationView

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val navHostFragment: NavHostFragment =
            supportFragmentManager.findFragmentById(R.id.fragment_container) as 
        NavHostFragment
       val navController: NavController = navHostFragment.navController

       val bottom_nav = findViewById<BottomNavigationView>(R.id.bottom_nav)
       bottom_nav.setupWithNavController(navController)
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
    val navController = findNavController(R.id.fragment_container)
    return item.onNavDestinationSelected(navController)
            || super.onOptionsItemSelected(item)
}

导航图配置

<?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.xml"
    app:startDestination="@id/crimeListFragment">

    <fragment
        android:id="@+id/crimeListFragment"
        android:name="com.andpro.android.criminalintent.CrimeListFragment"
        android:label="fragment_crime_list"
        tools:layout="@layout/fragment_crime_list" >
        <action
            android:id="@+id/action_crimeListFragment_to_crimeDetailFragment"
            app:destination="@id/crimeDetailFragment" />
    </fragment>
    <fragment
        android:id="@+id/crimeDetailFragment"
        android:name="com.andpro.android.criminalintent.CrimeDetailFragment"
        android:label="CrimeDetailFragment" >
        <argument
            android:name="crime_id"
            app:argType="java.util.UUID" />
        <action
            android:id="@+id/action_crimeDetailFragment_to_datePicker"
            app:destination="@id/datePicker" />
    </fragment>
    <dialog
        android:id="@+id/datePicker"
        android:name="com.andpro.android.criminalintent.DatePicker"
        android:label="DatePicker" >
        <argument
            android:name="crime"
            app:argType="com.andpro.android.criminalintent.CrimeClass" />
    </dialog>
</navigation>

报错信息

FATAL EXCEPTION: main
Process: com.andpro.android.criminalintent, PID: 30469
java.lang.IllegalArgumentException: Required argument "crime_id" is missing and does not have an android:defaultValue
    at com.andpro.android.criminalintent.CrimeDetailFragmentArgs$Companion.fromBundle(CrimeDetailFragmentArgs.kt:63)
    at com.andpro.android.criminalintent.CrimeDetailFragment.onCreate(CrimeDetailFragment.kt:31)
    at androidx.fragment.app.Fragment.performCreate(Fragment.java:3099)
    at androidx.fragment.app.FragmentStateManager.create(FragmentStateManager.java:524)
    at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:282)
    at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:2214)
    at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:2115)
    at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:2052)
    at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:703)
    at android.os.Handler.handleCallback(Handler.java:958)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loopOnce(Looper.java:230)
    at android.os.Looper.loop(Looper.java:319)
    at android.app.ActivityThread.main(ActivityThread.java:8919)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:578)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1103)

解决方案

问题核心是setupWithNavController会直接触发无参数的导航动作,无法自动传递crime_id参数。需要手动拦截底部导航的点击事件,构建带参数的导航请求。

修改MainActivity代码

package com.andpro.android.criminalintent

import android.os.Bundle
import android.view.MenuItem
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.fragment.NavHostFragment
import androidx.navigation.ui.onNavDestinationSelected
import com.google.android.material.bottomnavigation.BottomNavigationView
import java.util.UUID

class MainActivity : AppCompatActivity() {
    private lateinit var navController: NavController

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

        val navHostFragment: NavHostFragment =
            supportFragmentManager.findFragmentById(R.id.fragment_container) as NavHostFragment
        navController = navHostFragment.navController

        val bottom_nav = findViewById<BottomNavigationView>(R.id.bottom_nav)
        // 替换自动绑定为手动点击监听
        bottom_nav.setOnItemSelectedListener { menuItem ->
            when (menuItem.itemId) {
                R.id.crimeListFragment -> {
                    navController.navigate(R.id.crimeListFragment)
                    true
                }
                R.id.crimeDetailFragment -> {
                    // 替换为你实际需要传递的UUID(比如从Crime数据源获取默认ID)
                    val targetCrimeId = UUID.randomUUID() 
                    val args = CrimeDetailFragmentArgs.Builder(targetCrimeId).build()
                    navController.navigate(R.id.crimeDetailFragment, args.toBundle())
                    true
                }
                else -> menuItem.onNavDestinationSelected(navController) || super.onOptionsItemSelected(menuItem)
            }
        }
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return item.onNavDestinationSelected(navController)
                || super.onOptionsItemSelected(item)
    }
}

关键说明

  1. 移除自动绑定:删除bottom_nav.setupWithNavController(navController),避免无参数导航。
  2. 手动处理点击事件:通过setOnItemSelectedListener拦截每个菜单项的点击,针对CrimeDetailFragment的点击单独处理。
  3. 构建参数Bundle:使用Navigation自动生成的CrimeDetailFragmentArgs类(需确保项目已同步,让Android Studio生成该类),传入目标UUID后转换为Bundle,再调用navigate方法。
  4. 替换示例UUID:将代码中的UUID.randomUUID()替换为业务逻辑中实际需要传递的UUID(比如从Crime列表中获取第一个条目ID)。

内容的提问来源于stack exchange,提问作者Cmx Cix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 05:37:05