如何在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(); } }); } }
关键说明
- 接口回调优势:Adapter只负责UI渲染和触发事件,不依赖具体Fragment,避免耦合和内存泄漏。
- FragmentResult正确用法:必须从已绑定到FragmentManager的Fragment实例调用
setFragmentResult,不能用新建的未挂载实例。 - 异步回调处理:FragmentResultListener是异步触发的,必须在回调内部处理后续数据加载逻辑,不能在
onCreateView直接使用未赋值的muscleKey。 - 数据库引用修正:
databaseReference.child("xxx")不会修改原引用,必须重新赋值给新变量才能指向目标子节点。
内容的提问来源于stack exchange,提问作者user19595313
相关产品推荐
相关产品推荐

