RecyclerView点击项弹出AddNewHabit时遇Fragment未附加异常求助
问题解决:Fragment has not been attached yet 错误
错误原因
在HabitsAdapter的editHabit方法中,你尝试调用fragment.getChildFragmentManager()来显示AddNewHabit对话框,但此时新创建的AddNewHabit实例还未附加到任何Activity或Fragment上,无法获取有效的FragmentManager,因此抛出异常。
解决方案
核心是使用宿主Fragment(HabitsFragment)的FragmentManager来显示对话框,而非尝试从未附加的对话框Fragment自身获取。具体步骤如下:
1. 修改HabitsAdapter构造函数,传入FragmentManager
将Adapter的构造函数改为接收FragmentManager,替换原有的Activity参数,因为对话框是作为HabitsFragment的子Fragment展示,使用宿主Fragment的ChildFragmentManager更符合生命周期管理。
2. 在HabitsFragment中传递正确的FragmentManager
创建Adapter实例时,传入HabitsFragment的getChildFragmentManager()。
3. 在editHabit方法中使用传入的FragmentManager显示对话框
替换原来的fragment.getChildFragmentManager()为传入的FragmentManager实例。
额外优化
- 给
AddNewHabit添加带参数的newInstance方法,规范参数传递。 - 对话框的取消按钮直接调用
dismiss(),无需手动移除Fragment。
修改后的关键代码片段
HabitsAdapter.java 修改部分
public class HabitsAdapter extends RecyclerView.Adapter<HabitsAdapter.ViewHolder> { private List<HabitModel> mHabitList; private FragmentManager mFragmentManager; // 替换原mActivity private DataBaseHandler db; // 修改构造函数 public HabitsAdapter(DataBaseHandler db, FragmentManager fragmentManager){ this.db = db; this.mFragmentManager = fragmentManager; } // ... 其他代码不变 ... public void editHabit(int position){ HabitModel habit = mHabitList.get(position); // 使用带参数的newInstance方法传递数据 AddNewHabit fragment = AddNewHabit.newInstance(habit.getId(), habit.getTitle(), habit.getDescription()); // 使用传入的FragmentManager显示对话框 fragment.show(mFragmentManager, AddNewHabit.TAG); } // ... 其他代码不变 ... }
HabitsFragment.java 修改部分
在onViewCreated方法中创建Adapter时传入getChildFragmentManager():
@Override public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); db = new DataBaseHandler(getActivity()); db.openDatabase(); mAddTaskBtn = (ImageButton) view.findViewById(R.id.add_new_habit_btn); mAddTaskBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { AddNewHabit.newInstance().show(getChildFragmentManager(), AddNewHabit.TAG); } }); mRecyclerView = (RecyclerView) view.findViewById(R.id.habit_recyclerview); mRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); // 修改这里,传入getChildFragmentManager() mHabitsAdapter = new HabitsAdapter(db, getChildFragmentManager()); mRecyclerView.setAdapter(mHabitsAdapter); updateRecyclerView(); }
AddNewHabit.java 修改部分
添加带参数的newInstance方法,并优化取消按钮逻辑:
public class AddNewHabit extends BottomSheetDialogFragment { public static final String TAG = "com.unicode.android.wodehabit.action_bottom_dialog"; // ... 其他代码不变 ... // 新增带参数的newInstance方法 public static AddNewHabit newInstance(int id, String habit, String description) { AddNewHabit fragment = new AddNewHabit(); Bundle bundle = new Bundle(); bundle.putInt("id", id); bundle.putString("habit", habit); bundle.putString("description", description); fragment.setArguments(bundle); return fragment; } // ... 其他代码不变 ... @Override public void onViewCreated(View view, Bundle saveInstanceState) { super.onViewCreated(view, saveInstanceState); // ... 其他代码不变 ... cancelBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { // 直接调用dismiss关闭对话框,无需手动移除 dismiss(); } }); // ... 其他代码不变 ... } // ... 其他代码不变 ... }
为什么这样修改有效
- 使用宿主Fragment的
getChildFragmentManager()确保对话框Fragment被正确附加到宿主Fragment的生命周期中,避免未附加的异常。 - 通过带参数的
newInstance方法传递数据,符合Fragment的最佳实践,避免直接操作Fragment的内部状态。 - 使用
dismiss()关闭对话框是BottomSheetDialogFragment的标准方式,比手动移除Fragment更安全。
内容的提问来源于stack exchange,提问作者LuCC
相关产品推荐
相关产品推荐

