从Dialog调用Activity方法时触发IndexOutOfBoundsException异常的原因及解决办法
哦,我一眼就看到问题出在哪了!你在ConfirmDeleteDialog里手动创建了一个新的MainActivity实例:mainActivity = new MainActivity();——这完全是错误的操作!
这个新创建的MainActivity根本不是当前正在运行的那个Activity对象,它的allStock列表是全新初始化的空列表,没有从数据库加载任何数据,所以当你调用mainActivity.deleteItemRow(position)时,allStock.get(position)自然就会抛出IndexOutOfBoundsException,因为列表大小是0,而你传入的position是6。
而直接在MainActivity里调用deleteItemRow时,用的是当前Activity的实例,它的allStock已经通过db.getAllStock()加载了数据,所以一切正常。
修复方案一:使用接口回调(推荐,低耦合)
这种方式遵循Android组件设计规范,降低Dialog和Activity的耦合度:
- 在
ConfirmDeleteDialog中定义回调接口,并持有接口引用:
public class ConfirmDeleteDialog extends DialogFragment { private OnDeleteConfirmListener mListener; int position; Button no, yes; // 当Dialog绑定到Activity时,获取回调实例 @Override public void onAttach(@NonNull Context context) { super.onAttach(context); try { mListener = (OnDeleteConfirmListener) context; } catch (ClassCastException e) { throw new ClassCastException(context.toString() + " 必须实现OnDeleteConfirmListener接口"); } } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { LayoutInflater inflater = getActivity().getLayoutInflater(); View v = inflater.inflate(R.layout.dialog_confirm_delete, null); Bundle bundle = getArguments(); if (bundle != null) { position = bundle.getInt("position"); } no = v.findViewById(R.id.btnNo); yes = v.findViewById(R.id.btnYes); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setView(v); no(); yes(); return builder.create(); } private void no() { no.setOnClickListener(v -> dismiss()); } private void yes() { yes.setOnClickListener(v -> { if (mListener != null) { mListener.onDeleteConfirmed(position); } dismiss(); }); } // 定义删除确认的回调接口 public interface OnDeleteConfirmListener { void onDeleteConfirmed(int position); } // 解绑时清空引用,避免内存泄漏 @Override public void onDetach() { super.onDetach(); mListener = null; } }
- 让
MainActivity实现这个回调接口,处理删除逻辑:
public class MainActivity extends AppCompatActivity implements StockViewInterface, ConfirmDeleteDialog.OnDeleteConfirmListener { // ... 已有代码 ... @Override public void onDeleteConfirmed(int position) { deleteItemRow(position); } // ... 已有代码 ... }
修复方案二:直接获取当前Activity实例(简单直接)
如果你觉得接口回调有点繁琐,可以直接获取当前运行的Activity实例,不要手动创建新的:
public class ConfirmDeleteDialog extends DialogFragment { private MainActivity mainActivity; int position; Button no, yes; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); // 获取当前绑定的MainActivity实例 mainActivity = (MainActivity) getActivity(); } @NonNull @Override public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) { LayoutInflater inflater = getActivity().getLayoutInflater(); View v = inflater.inflate(R.layout.dialog_confirm_delete, null); Bundle bundle = getArguments(); if (bundle != null) { position = bundle.getInt("position"); } no = v.findViewById(R.id.btnNo); yes = v.findViewById(R.id.btnYes); AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); builder.setView(v); no(); yes(); return builder.create(); } private void no() { no.setOnClickListener(v -> dismiss()); } private void yes() { yes.setOnClickListener(v -> { if (mainActivity != null) { mainActivity.deleteItemRow(position); } dismiss(); }); } @Override public void onDetach() { super.onDetach(); mainActivity = null; // 清空引用避免内存泄漏 } }
额外小优化
你在deleteItemRow方法里同时调用了notifyItemRemoved(position)和notifyDataSetChanged(),其实只需要notifyItemRemoved(position)就足够了——它会自动处理列表的位置更新,而notifyDataSetChanged()会刷新整个列表,效率更低。
内容的提问来源于stack exchange,提问作者rholmes97
相关产品推荐
相关产品推荐

