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

从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的耦合度:

  1. 在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;
    }
}
  1. 让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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 19:08:19