RecyclerView编辑列表项时getAdapterPosition()触发ArrayIndexOutOfBounds异常
嘿,咱们来搞定你遇到的这个RecyclerView数组越界问题!你怀疑getAdapterPosition()是问题根源,这点完全没错——这确实是这类bug的高发区。
为啥会出问题?
RecyclerView的ViewHolder会被复用,当你触发编辑操作时,如果对应的视图已经被回收,或者列表数据已经发生了更新(比如删了某一项、移动了位置),getAdapterPosition()可能会返回RecyclerView.NO_POSITION(也就是-1),或者返回一个过时的位置索引。用这个无效索引去操作数据集合,自然就会抛出数组越界异常。
具体修复方案
1. 先检查位置是否有效
在调用editClassnameAt()之前,一定要先判断位置是不是合法的:
int position = holder.getAdapterPosition(); if (position == RecyclerView.NO_POSITION) { // 位置无效,直接返回,别往下走了 return; } // 确认没问题再执行编辑 editClassnameAt(position, newClassName);
2. 改用getBindingAdapterPosition()(更靠谱)
如果你用的是AndroidX版本的RecyclerView(现在基本都是),getAdapterPosition()已经被标记为过时了,推荐用getBindingAdapterPosition()替代。它能更精准地返回当前ViewHolder在绑定的Adapter中的位置,尤其是在使用ConcatAdapter这类多Adapter组合的场景下,能避免位置混淆:
int position = holder.getBindingAdapterPosition(); if (position == RecyclerView.NO_POSITION) { return; } editClassnameAt(position, newClassName);
3. 给editClassnameAt()加个安全防护
也有可能你的editClassnameAt()方法本身没做边界检查,直接就去访问数据集合了,比如这样:
// 错误示例:没检查position是否在有效范围内 public void editClassnameAt(int position, String newName) { mClassNames.get(position).setName(newName); // 这里直接访问,很容易越界 notifyItemChanged(position); } // 修复后:加上边界校验 public void editClassnameAt(int position, String newName) { if (position < 0 || position >= mClassNames.size()) { Log.w(TAG, "无效的位置索引: " + position); return; } mClassNames.get(position).setName(newName); notifyItemChanged(position); }
4. 异步场景别依赖位置(比如弹窗编辑)
如果你的编辑操作是异步触发的——比如弹出一个输入Dialog,用户输入完才执行编辑——这时候ViewHolder可能已经被复用,位置早就失效了。这种情况最好在触发编辑时,保存当前数据项的唯一标识(比如item的ID),而不是依赖位置:
// 假设你的数据模型有唯一ID字段 public class ClassItem { private String id; private String className; // getter、setter方法 } // 点击编辑按钮时,先拿到当前item的ID holder.editBtn.setOnClickListener(v -> { int position = holder.getBindingAdapterPosition(); if (position != RecyclerView.NO_POSITION) { ClassItem currentItem = mClassNames.get(position); showEditDialog(currentItem.getId()); } }); // 当用户确认编辑后,通过ID找到对应的位置再更新 private void onEditConfirm(String itemId, String newClassName) { for (int i = 0; i < mClassNames.size(); i++) { if (mClassNames.get(i).getId().equals(itemId)) { mClassNames.get(i).setClassName(newClassName); notifyItemChanged(i); break; } } }
总结
按照上面的步骤来:先确保获取的位置有效,改用更靠谱的getBindingAdapterPosition(),给editClassnameAt()加边界检查,异步场景用唯一ID定位——基本上就能解决这个数组越界的问题了!
内容的提问来源于stack exchange,提问作者Aham_Uzoma

