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

解决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查找失败的问题。

  1. 改造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逻辑保持原有实现不变
}
  1. 在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:

  1. 改造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)
        }
    }
}
  1. 在MainFragment中初始化Adapter时,直接传入当前Fragment绑定的NavController
val adapter = MainAdapter(yourMovieDataList, findNavController())
recyclerView.adapter = adapter

注意:该方案虽然能快速解决报错,但如果页面销毁重建时NavController实例变化,可能会引发内存泄漏或导航失效,优先使用第一种回调方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 23:36:07