RecyclerView传onBindViewHolder的ArrayList大小给getItemCount
问题核心原因
- 你在
onBindViewHolder里创建的newStatusList、size都是方法局部变量,作用域仅限当前方法执行期间,getItemCount()根本访问不到这些值,自然返回无效结果。 - 每次
onBindViewHolder触发时你都重新读数据库创建新列表,Adapter本身没有持有持久的数据源引用,删除操作的改动根本不会留存,所以会出现删完条目又重新生成的问题。 onBindViewHolder的职责只是绑定指定位置的item数据,不适合做全量数据初始化、全量列表删改这类操作,频繁在这里查库还会导致滑动卡顿。
可行实现方案
核心思路是把列表数据源作为Adapter的全局成员变量维护,构造函数里只做一次初始数据加载,删除操作直接修改成员数据源、同步更新数据库后通知列表刷新即可,不需要在构造函数里访问position。
完整实现参考:
public class ChecklistAdapter extends RecyclerView.Adapter<ChecklistAdapter.VH> { // 声明为Adapter成员变量,所有内部方法都能访问 private final ArrayList<String> statusList; private final DbHelper dbHelper; private final long currentChecklistId; // 构造函数只做初始化,不需要position参数 public ChecklistAdapter(DbHelper dbHelper, long checklistId) { this.dbHelper = dbHelper; this.currentChecklistId = checklistId; // 初始化时只读一次数据库加载全量数据 ChecklistHelper checklistHelper = dbHelper.getChecklists(checklistId); String rawStatus = checklistHelper.getStatus(); String[] statusArr = rawStatus.split("\n"); statusList = new ArrayList<>(Arrays.asList(statusArr)); } @NonNull @Override public VH onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { // 正常写你的item布局加载逻辑 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_checklist, parent, false); return new VH(view); } @Override public void onBindViewHolder(@NonNull VH holder, int position) { // 只做当前position的数据绑定,不要在这里查全量库、重建列表 String itemContent = statusList.get(position); holder.tvStatus.setText(itemContent); // 删除逻辑绑定到对应控件的点击事件上,点击时再拿当前位置 holder.btnDelete.setOnClickListener(v -> { // 用getAdapterPosition拿实时位置,避免位置错乱 int adapterPos = holder.getAdapterPosition(); if (adapterPos == RecyclerView.NO_POSITION) return; // 1. 先删内存里的数据源 statusList.remove(adapterPos); // 2. 同步更新数据库持久化 StringBuilder newStatusBuilder = new StringBuilder(); for (int i = 0; i < statusList.size(); i++) { newStatusBuilder.append(statusList.get(i)); if (i != statusList.size() - 1) newStatusBuilder.append("\n"); } ChecklistHelper updateBean = new ChecklistHelper(); updateBean.setId(currentChecklistId); updateBean.setStatus(newStatusBuilder.toString()); dbHelper.updateChecklist(updateBean); // 替换成你自己的数据库更新方法 // 3. 通知UI刷新 notifyItemRemoved(adapterPos); // 刷新后续item位置,避免角标错位 notifyItemRangeChanged(adapterPos, statusList.size() - adapterPos); }); } @Override public int getItemCount() { // 直接返回成员列表的长度,不需要单独维护size变量 return statusList.size(); } static class VH extends RecyclerView.ViewHolder { TextView tvStatus; ImageView btnDelete; public VH(@NonNull View itemView) { super(itemView); tvStatus = itemView.findViewById(R.id.tv_status); btnDelete = itemView.findViewById(R.id.btn_delete); } } }
注意事项
- 不要单独维护一个独立的
size变量,直接调用数据源的size()方法返回即可,避免出现数据源修改了但size值没同步的不一致问题。 - 列表操作的顺序要对:先修改内存中的数据源,再更新数据库,最后调用
notify系列方法刷新UI,顺序错了会出现数据和UI不匹配的崩溃或显示异常。 - 不要在
onBindViewHolder里做全量数据查询,这个方法会在item滑入屏幕时频繁调用,冗余IO会严重影响列表滑动流畅度。 - 删除操作不要直接用
onBindViewHolder传入的position参数,用holder.getAdapterPosition()拿实时位置,避免列表动画过程中位置不准删错条目。
内容的提问来源于stack exchange,提问作者nano tech
相关产品推荐
相关产品推荐

