如何通过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) } }
关键说明
- 移除自动绑定:删除
bottom_nav.setupWithNavController(navController),避免无参数导航。 - 手动处理点击事件:通过
setOnItemSelectedListener拦截每个菜单项的点击,针对CrimeDetailFragment的点击单独处理。 - 构建参数Bundle:使用Navigation自动生成的
CrimeDetailFragmentArgs类(需确保项目已同步,让Android Studio生成该类),传入目标UUID后转换为Bundle,再调用navigate方法。 - 替换示例UUID:将代码中的
UUID.randomUUID()替换为业务逻辑中实际需要传递的UUID(比如从Crime列表中获取第一个条目ID)。
内容的提问来源于stack exchange,提问作者Cmx Cix
相关产品推荐
相关产品推荐

