解决Android Navigation报does not have a NavController set错误
报错根因
异常提示View does not have a NavController set的核心原因:
Navigation.findNavController()的实现逻辑是从传入的View节点开始,向上遍历整个视图树,查找绑定了NavController的NavHost节点。你在MainAdapter的onBindViewHolder里直接传入holder.itemView调用该方法时,RecyclerView的itemView还未完成和宿主Fragment视图树的关联,向上遍历找不到NavHost绑定的NavController实例,就会抛出该异常。- 本质是职责越界问题:导航逻辑属于页面(Fragment/Activity)的职责,不应该写在列表适配器中,适配器只需要负责列表项渲染、把点击事件透传给宿主页面即可。
- 额外隐患:你当前的跳转代码只给导航Action赋值了
releaseDate一个参数,导航图中DetailFragment配置的avatar、adult两个参数没有赋值,即使解决了导航报错,跳转后这两个字段也只会显示默认值,拿不到真实业务数据。
可落地方案
推荐方案:接口回调透传点击事件(符合架构规范,无内存泄漏风险)
这种方案把导航逻辑完全交还给宿主MainFragment处理,从根源上避免NavController查找失败的问题。
- 改造MainAdapter,去掉内部导航逻辑,新增点击回调作为构造参数
// 替换成你实际的列表数据实体类名 class MainAdapter( private val dataList: List<MovieData>, private val onItemClickListener: (resultData: MovieData) -> Unit ) : RecyclerView.Adapter<MainAdapter.DataViewHolder>() { override fun onBindViewHolder(holder: DataViewHolder, position: Int) { val resultData = dataList[position] holder.bind(resultData) holder.itemView.setOnClickListener { // 点击时仅触发回调,不处理任何导航逻辑 onItemClickListener(resultData) } } // 其余onCreateViewHolder、DataViewHolder逻辑保持原有实现不变 }
- 在MainFragment中初始化Adapter时实现回调,在回调中编写导航逻辑
// 初始化RecyclerView的代码块中 val adapter = MainAdapter(yourMovieDataList) { resultData -> // Fragment扩展方法可直接获取绑定的NavController,不存在查找失败问题 val navAction = MainFragmentDirections.actionMainFragmentToDetailFragment().apply { releaseDate = resultData.release_date avatar = resultData.poster_path // 替换成你实体类中对应的封面图字段 adult = resultData.isAdult // 替换成你实体类中对应的成人标识字段 } findNavController().navigate(navAction) } recyclerView.adapter = adapter
临时快速修复方案(不推荐长期使用)
如果需要快速验证逻辑,可以直接把NavController实例作为参数传入Adapter,避免在Adapter内部查找NavController:
- 改造MainAdapter构造函数,新增NavController入参
class MainAdapter( private val dataList: List<MovieData>, private val navController: NavController ) : RecyclerView.Adapter<MainAdapter.DataViewHolder>() { override fun onBindViewHolder(holder: DataViewHolder, position: Int) { val resultData = dataList[position] holder.bind(resultData) holder.itemView.setOnClickListener{ val action = MainFragmentDirections.actionMainFragmentToDetailFragment().apply { releaseDate = resultData.release_date avatar = resultData.poster_path adult = resultData.isAdult } navController.navigate(action) } } }
- 在MainFragment中初始化Adapter时,直接传入当前Fragment绑定的NavController
val adapter = MainAdapter(yourMovieDataList, findNavController()) recyclerView.adapter = adapter
注意:该方案虽然能快速解决报错,但如果页面销毁重建时NavController实例变化,可能会引发内存泄漏或导航失效,优先使用第一种回调方案。
内容的提问来源于stack exchange,提问作者isa
相关产品推荐
相关产品推荐

