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

使用Navigation Components实现RecyclerView点击切换Fragment报错

报错原因
  • 核心问题是你在RecyclerViewAdapterForClassList内部直接写导航逻辑、硬引用SecondFragment实例找NavController:
    1. Adapter不属于导航组件的生命周期关联对象,直接持有外部Fragment强引用,很容易因为Fragment视图销毁、实例状态异常(比如已经被移除出返回栈)导致NavController查找失败,还会引发内存泄漏。
    2. 你没有从当前视图树绑定的导航宿主获取NavController,直接传入硬编码的Fragment实例,会出现NavController和当前导航宿主不匹配的崩溃。
    3. 如果排除上面的问题,还要检查nav_graph配置里action_SecondFragment_to_studentListFragment这个action是否真的挂载在SecondFragment对应的destination节点下,是否存在id写错的情况。
正确实现方案

1. 改造Adapter,剥离导航逻辑

Adapter只负责视图渲染和点击事件分发,不要在内部持有Fragment/Activity强引用、写页面跳转逻辑,示例代码(Kotlin写法逻辑完全一致):

public class RecyclerViewAdapterForClassList extends RecyclerView.Adapter<RecyclerViewAdapterForClassList.VH> {
    private List<ClassBean> classList;
    // 定义点击回调接口
    public interface OnItemClickListener {
        void onItemClick(ClassBean itemData);
    }
    private OnItemClickListener clickListener;

    public RecyclerViewAdapterForClassList(List<ClassBean> list, OnItemClickListener listener) {
        this.classList = list;
        this.clickListener = listener;
    }

    @NonNull
    @Override
    public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_class_list, parent, false);
        return new VH(view);
    }

    @Override
    public void onBindViewHolder(@NonNull VH holder, int position) {
        ClassBean item = classList.get(position);
        // 正常绑定视图数据即可
        holder.tvClassName.setText(item.getClassName());
    }

    @Override
    public int getItemCount() {
        return classList == null ? 0 : classList.size();
    }

    class VH extends RecyclerView.ViewHolder {
        TextView tvClassName;
        public VH(@NonNull View itemView) {
            super(itemView);
            tvClassName = itemView.findViewById(R.id.tv_class_name);
            // 点击时触发回调,把数据抛给外部处理
            itemView.setOnClickListener(v -> {
                int pos = getAdapterPosition();
                if (pos != RecyclerView.NO_POSITION && clickListener != null) {
                    clickListener.onItemClick(classList.get(pos));
                }
            });
        }
    }
}

2. 在SecondFragment内处理导航逻辑

在Fragment自己的生命周期范围内初始化Adapter,在点击回调里获取NavController执行跳转,保证生命周期匹配:

public class SecondFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_second, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        RecyclerView rvClassList = view.findViewById(R.id.rv_class_list);
        rvClassList.setLayoutManager(new LinearLayoutManager(requireContext()));
        // 初始化Adapter,传入点击监听
        List<ClassBean> dataList = new ArrayList<>(); // 替换成你的真实数据源
        RecyclerViewAdapterForClassList adapter = new RecyclerViewAdapterForClassList(dataList, item -> {
            // 在Fragment自身上下文中找NavController,不会出现生命周期不匹配问题
            NavController navController = NavHostFragment.findNavController(SecondFragment.this);
            // 需要传参的话可以通过Bundle构造参数传入
            navController.navigate(R.id.action_SecondFragment_to_studentListFragment);
        });
        rvClassList.setAdapter(adapter);
    }
}
注意事项
  • 不要在Adapter中直接持有Fragment、Activity的强引用,所有业务逻辑、页面跳转都通过接口回调抛给对应页面处理,避免内存泄漏和生命周期不同步引发的崩溃。
  • 导航调用必须在Fragment视图创建完成后执行,禁止在onCreateView视图未返回时提前触发导航。
  • 如果导航依然报错,检查nav_graph配置:确认studentListFragment是SecondFragment的直接导航目的地,对应action的id和代码中引用的id完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:15:45