Android导航报错‘Doesn't have a navController set’原因及解决求助
问题分析与解决方案
核心问题原因
- 导航容器冲突:你在MainActivity里手动通过
supportFragmentManager将TaskListFragment添加到fragment_container,直接覆盖了NavHostFragment的导航管理,导致导航组件完全失效,navController自然无法正常工作;同时你只定义了navController却未使用,所以IDE提示未使用变量。 - Adapter语法错误:
TodoAdapter的onCreateViewHolder方法存在重复return的语法错误,会导致代码编译失败。 - 导航方式冗余:使用DeepLink实现简单的Fragment间跳转没必要,反而容易出错,直接通过导航ID跳转更可靠。
分步修复方案
1. 修复MainActivity,启用导航组件
删除手动添加Fragment的代码,让NavHostFragment负责所有页面导航,同时移除多余的FrameLayout(导航组件仅需NavHostFragment):
修改后的MainActivity.kt:
package com.bignerdranch.android.taskmaster import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import androidx.navigation.fragment.NavHostFragment import com.bignerdranch.android.taskmaster.databinding.ActivityMainBinding class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) // 让NavHostFragment自动加载startDestination指定的Fragment val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment val navController = navHostFragment.navController // 可添加此行绑定ActionBar导航,消除未使用提示 // setupActionBarWithNavController(navController) } // 若绑定了ActionBar,重写此方法支持返回键导航 // override fun onSupportNavigateUp(): Boolean { // val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment // return navHostFragment.navController.navigateUp() || super.onSupportNavigateUp() // } }
修改后的activity_main.xml:
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" xmlns:app="http://schemas.android.com/apk/res-auto" tools:context=".MainActivity" android:background="#FFF"> <androidx.fragment.app.FragmentContainerView 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:navGraph="@navigation/task_graph" /> </androidx.constraintlayout.widget.ConstraintLayout>
2. 修复TodoAdapter的语法错误
修改onCreateViewHolder方法,移除重复的return:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val itemTodoBinding = ItemTodoBinding.inflate(layoutInflater, parent, false) return TodoViewHolder(itemTodoBinding) }
3. 修改导航逻辑,直接通过ID跳转
在task_graph.xml中添加Fragment间的跳转action:
<?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" android:id="@+id/task_graph" app:startDestination="@id/taskListFragment"> <fragment android:id="@+id/taskListFragment" android:name="com.bignerdranch.android.taskmaster.TaskListFragment" android:label="TaskListFragment"> <!-- 添加跳转到TaskDetailFragment的action --> <action android:id="@+id/action_taskListFragment_to_taskDetailFragment" app:destination="@id/taskDetailFragment" /> </fragment> <fragment android:id="@+id/taskDetailFragment" android:name="com.bignerdranch.android.taskmaster.TaskDetailFragment" android:label="TaskDetailFragment"> <deepLink android:id="@+id/deepLink" app:uri="app://taskmaster.taskDetailFragment" /> </fragment> </navigation>
修改TodoAdapter中tvTodoTitle的点击事件,使用导航ID跳转:
tvTodoTitle.setOnClickListener { it.findNavController().navigate(R.id.action_taskListFragment_to_taskDetailFragment) }
4. 额外优化(可选:传递任务参数)
若需要将任务ID传递到TaskDetailFragment,在task_graph.xml添加参数:
<fragment android:id="@+id/taskDetailFragment" android:name="com.bignerdranch.android.taskmaster.TaskDetailFragment" android:label="TaskDetailFragment"> <argument android:name="taskId" android:defaultValue="-1" app:argType="integer" /> <deepLink android:id="@+id/deepLink" app:uri="app://taskmaster.taskDetailFragment" /> </fragment>
在Adapter中传递参数:
tvTodoTitle.setOnClickListener { val bundle = Bundle().apply { putInt("taskId", curTodo.id) // 假设Todo类包含id字段 } it.findNavController().navigate(R.id.action_taskListFragment_to_taskDetailFragment, bundle) }
在TaskDetailFragment中接收参数:
val taskId = arguments?.getInt("taskId", -1)
内容的提问来源于stack exchange,提问作者Владислава Черкасова
相关产品推荐
相关产品推荐

