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

RecyclerView删除项错位求助:点击删除指定项却删除上一项

RecyclerView 删除元素位置错误的修复方案

问题描述

我的RecyclerView从phpMyAdmin获取数据,在Adapter中添加了删除元素的代码,但点击删除按钮时,删除的是位置更高的元素——比如点击删除第5项,实际删除的是第6项。尝试添加holder.getAdapterPosition()但没有效果,求修复方法。

原Adapter代码

public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {

    Context context;
    ArrayList<Model> models;

    public MainAdapter(Context context, ArrayList<Model> models) {
        this.context = context;
        this.models = models;
    }

    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        View view = LayoutInflater.from(context).inflate(R.layout.item_layout, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int number) {

        holder.position.setText(models.get(number).getPosition());
        holder.id.setText(models.get(number).getId());
        holder.name.setText(models.get(number).getName());

        holder.cardview.setOnClickListener(view -> {
            Intent intent = new Intent(context, ActivitySecond.class);
            intent.putExtra("id", models.get(number).getId());
            context.startActivity(intent);
        });

        holder.delete.setOnClickListener(view -> {

            String url = "";
            StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
                    response -> Toast.makeText(context, "Success", Toast.LENGTH_SHORT).show(),
                    error -> Toast.makeText(context, "Error: " + error, Toast.LENGTH_SHORT).show()) {
                @Override
                public Map<String, String> getParams() {
                    Map<String, String> params = new HashMap<>();

                    params.put("position", models.get(number).getPosition());

                    return params;
                }
            };

            models.remove(number);
            notifyItemRemoved(number);
            notifyItemRangeChanged(holder.getAdapterPosition(), models.size());

            RequestQueue requestQueue = Volley.newRequestQueue(context);
            requestQueue.add(stringRequest);

        });
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder {
        TextView position, id, name;
        CardView cardview, delete;

        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            position = itemView.findViewById(R.id.position);
            id = itemView.findViewById(R.id.id);
            name = itemView.findViewById(R.id.name);
            cardview = itemView.findViewById(R.id.cardview);
            delete = itemView.findViewById(R.id.delete);
        }
    }

    public void clear() {
        int size = models.size();
        models.clear();
        notifyItemRangeRemoved(0, size);
    }
}

修复方案

问题根源是点击事件中直接使用onBindViewHolder的number参数(旧的静态位置),但RecyclerView的Item复用机制会导致该位置在事件触发时已失效。正确做法是依赖ViewHolder的实时位置,并调整操作顺序:

1. 获取实时有效位置

在删除点击事件中,通过holder.getAdapterPosition()获取当前Item的实时位置,先判断位置是否有效(避免Item已被移除的情况)。

2. 调整操作顺序

先获取要删除的元素数据(用于网络请求),再执行本地数据删除和RecyclerView通知,最后发起网络请求——防止数据删除后无法获取正确的请求参数。

3. 修正通知方法参数

notifyItemRangeChanged的起始位置应为被删除元素的位置,而非holder.getAdapterPosition()(此时Item已被移除,该位置无效)。

修改后的删除点击事件代码

holder.delete.setOnClickListener(view -> {
    // 获取当前Item的实时位置
    int currentPosition = holder.getAdapterPosition();
    // 检查位置是否有效,避免无效操作
    if (currentPosition == RecyclerView.NO_POSITION) {
        return;
    }

    // 先保存要删除的元素数据,避免数据移除后无法获取
    Model deletedModel = models.get(currentPosition);
    String positionParam = deletedModel.getPosition();

    // 执行本地数据删除并通知RecyclerView更新
    models.remove(currentPosition);
    notifyItemRemoved(currentPosition);
    // 通知从删除位置开始的所有Item更新位置信息
    notifyItemRangeChanged(currentPosition, models.size());

    // 发起网络删除请求
    String url = ""; // 替换为你的实际删除接口地址
    StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
            response -> Toast.makeText(context, "删除成功", Toast.LENGTH_SHORT).show(),
            error -> {
                Toast.makeText(context, "删除失败: " + error.getMessage(), Toast.LENGTH_SHORT).show();
                // 网络请求失败时回滚数据,保证本地与服务器数据一致
                models.add(currentPosition, deletedModel);
                notifyItemInserted(currentPosition);
                notifyItemRangeChanged(currentPosition, models.size());
            }) {
        @Override
        public Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            params.put("position", positionParam);
            return params;
        }
    };

    RequestQueue requestQueue = Volley.newRequestQueue(context);
    requestQueue.add(stringRequest);
});

额外优化建议

  • 将点击事件绑定移至ViewHolder构造函数中,避免onBindViewHolder重复绑定,进一步规避Item复用导致的位置问题。
  • 网络请求失败时添加数据回滚逻辑,确保本地数据与服务器数据状态一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:05:54