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

如何在RecyclerView Adapter中调用getParentFragmentManager()与Fragment交互?

RecyclerView Adapter向Fragment传值崩溃的解决方案

你崩溃的核心原因是新建的MusclesFragment实例未被添加到FragmentManager,调用getParentFragmentManager()返回null,执行setFragmentResult时触发空指针异常。另外代码还存在几处逻辑问题,下面一步步修正:

一、修复Adapter的点击回调逻辑

不要在Adapter里直接创建Fragment实例,改用接口回调让所属Fragment处理事件,解耦且避免空指针:

public class MusclesListAdapter extends RecyclerView.Adapter<MusclesListAdapter.MuscleViewHolder> {
    private Context context;
    private List<MusclesKeys> musclesKeysList;
    private OnMuscleClickListener listener; // 定义点击回调接口

    // 新增点击回调接口
    public interface OnMuscleClickListener {
        void onMuscleClicked(String muscleKey);
    }

    // 修改构造方法,传入回调实例
    public MusclesListAdapter(Context context, List<MusclesKeys> musclesKeysList, OnMuscleClickListener listener) {
        this.context = context;
        this.musclesKeysList = musclesKeysList;
        this.listener = listener;
    }

    @NonNull
    @Override
    public MuscleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(context);
        View view = inflater.inflate(R.layout.muscle_group_row, parent, false);
        return new MuscleViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull MuscleViewHolder holder, int position) {
        holder.muscleBtn.setImageResource(musclesKeysList.get(position).image);
        holder.muscleBtn.setOnClickListener(view -> {
            // 触发回调,传递选中的肌肉键
            String muscleKey = musclesKeysList.get(position).getKey().toString();
            listener.onMuscleClicked(muscleKey);
        });
    }

    @Override
    public int getItemCount() {
        return musclesKeysList.size();
    }

    public class MuscleViewHolder extends RecyclerView.ViewHolder {
        ImageView muscleBtn;

        public MuscleViewHolder(@NonNull View itemView) {
            super(itemView);
            muscleBtn = itemView.findViewById(R.id.muscle_btn);
        }
    }
}

在MusclesFragment中实现接口,处理跳转和FragmentResult发送:

public class MusclesFragment extends Fragment implements MusclesListAdapter.OnMuscleClickListener {

    // ... 其他原有代码 ...

    // 初始化RecyclerView时传入回调
    private void initRecyclerView() {
        MusclesListAdapter adapter = new MusclesListAdapter(getContext(), musclesKeysList, this);
        recyclerView.setAdapter(adapter);
    }

    // 实现回调方法
    @Override
    public void onMuscleClicked(String muscleKey) {
        // 用当前Fragment的FragmentManager发送结果
        Bundle bundle = new Bundle();
        bundle.putString("muscleName", muscleKey);
        getParentFragmentManager().setFragmentResult("muscleKey", bundle);

        // 跳转ExercisesFragment
        ExercisesFragment fragment = new ExercisesFragment();
        getParentFragmentManager().beginTransaction()
                .replace(R.id.fragmentContainerView, fragment, null)
                .addToBackStack(null)
                .commit();
    }
}

二、修复ExercisesFragment的逻辑问题

原代码存在异步回调未处理、switch穿透、数据库引用错误三个核心问题,修正如下:

public class ExercisesFragment extends Fragment {
    private List<ExercisesKeys> exercisesList;
    private RecyclerView recyclerView;
    private DatabaseReference databaseReference;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_exercises, container, false);

        exercisesList = new ArrayList<>();
        recyclerView = v.findViewById(R.id.exercises_rv);
        recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));
        recyclerView.setHasFixedSize(true);
        databaseReference = FirebaseDatabase.getInstance().getReference();

        // 在FragmentResult回调中处理数据加载(回调是异步的,不能在onCreateView直接使用muscleKey)
        getParentFragmentManager().setFragmentResultListener("muscleKey", this, (requestKey, result) -> {
            String muscleKey = result.getString("muscleName");
            if (muscleKey != null) {
                loadExercisesByMuscle(muscleKey);
            }
        });

        return v;
    }

    // 单独提取加载数据的方法
    private void loadExercisesByMuscle(String muscleKey) {
        exercisesList.clear();
        // 正确指向目标子节点(原代码未重新赋值引用,始终指向根节点)
        DatabaseReference targetRef = databaseReference.child(muscleKey);
        targetRef.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot snapshot) {
                exercisesList.clear();
                for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                    ExercisesKeys exercisesKeys = new ExercisesKeys(dataSnapshot.getValue().toString());
                    exercisesList.add(exercisesKeys);
                }
                ExercisesListAdapter adapter = new ExercisesListAdapter(requireContext(), exercisesList);
                recyclerView.setAdapter(adapter);
            }

            @Override
            public void onCancelled(@NonNull DatabaseError error) {
                Toast.makeText(requireContext(), "加载失败", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

关键说明

  1. 接口回调优势:Adapter只负责UI渲染和触发事件,不依赖具体Fragment,避免耦合和内存泄漏。
  2. FragmentResult正确用法:必须从已绑定到FragmentManager的Fragment实例调用setFragmentResult,不能用新建的未挂载实例。
  3. 异步回调处理:FragmentResultListener是异步触发的,必须在回调内部处理后续数据加载逻辑,不能在onCreateView直接使用未赋值的muscleKey。
  4. 数据库引用修正:databaseReference.child("xxx")不会修改原引用,必须重新赋值给新变量才能指向目标子节点。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 19:48:17