如何通过代码一次性修改RecyclerView所有项,解决数据集超10个时长按崩溃问题
崩溃根因
你当前写法的问题完全出在对RecyclerView复用机制的错误使用上:findViewHolderForAdapterPosition()只能获取到当前屏幕可见(+少量预加载)的列表项对应的ViewHolder实例,超出屏幕的项没有可复用的ViewHolder,调用该方法会直接返回null,后续你没有做空判断就调用方法,必然触发空指针异常。
数据少于10项时刚好铺满一屏,所有项都有对应ViewHolder所以运行正常,数据量超过一屏后就会崩溃。
修复方案(完全保留原有交互逻辑)
不要直接遍历修改ViewHolder的视图状态,所有和列表项展示相关的逻辑都应该放到Adapter的onBindViewHolder中处理,符合RecyclerView的设计规范,无论多大数据集都不会出问题。
第一步:在RecyclerAdapter中新增状态变量
public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.MyViewHolder> { // 原有变量保留,新增以下两个变量 // 标记当前是否处于删除选择模式 private boolean isInDeleteMode = false; // 存储用户选中要删除的项位置,也可以换成存储单词id,根据你的业务调整 private List<Integer> selectedDeletePositions = new ArrayList<>(); // 新增两个变量的get/set方法 public boolean isInDeleteMode() { return isInDeleteMode; } public void setInDeleteMode(boolean inDeleteMode) { isInDeleteMode = inDeleteMode; // 切换模式时清空选中状态 selectedDeletePositions.clear(); } public List<Integer> getSelectedDeletePositions() { return selectedDeletePositions; } // ... 原有其他代码保留 }
第二步:修改onBindViewHolder方法,添加删除模式相关的视图绑定逻辑
@Override public void onBindViewHolder(@NonNull MyViewHolder holder, int position) { // 你原本绑定单词数据的逻辑完全保留,以下是新增逻辑 RadioButton deleteRb = holder.getView().findViewById(R.id.delete_selector); if (isInDeleteMode) { // 删除模式下显示单选按钮 deleteRb.setVisibility(View.VISIBLE); deleteRb.setChecked(selectedDeletePositions.contains(position)); } else { // 普通模式下隐藏单选按钮 deleteRb.setVisibility(View.INVISIBLE); deleteRb.setChecked(false); } // 单选按钮的点击选中逻辑也放到这里处理 deleteRb.setOnClickListener(v -> { if (selectedDeletePositions.contains(position)) { selectedDeletePositions.remove(Integer.valueOf(position)); } else { selectedDeletePositions.add(position); } // 只刷新当前点击的项,性能更高 notifyItemChanged(position); }); }
第三步:替换你原来的长按事件逻辑
删掉原来遍历所有ViewHolder的代码,替换为以下逻辑:
@Override public void onLongItemClick(int adapterPosition) { // 切换删除模式状态 adapter.setInDeleteMode(!adapter.isInDeleteMode()); // 刷新所有可见项更新视图状态 adapter.notifyItemRangeChanged(0, adapter.getItemCount()); longClicked = adapter.isInDeleteMode(); }
第四步:删除数据逻辑补充
你需要执行删除操作时,直接从adapter.getSelectedDeletePositions()拿到所有选中的项,对应从你的数据源中取出单词数据删除Room数据库,删除完成后更新Adapter的数据源,调用notifyDataSetChanged()或者精准的notifyItemRemoved()即可。
内容的提问来源于stack exchange,提问作者DWScmack
相关产品推荐
相关产品推荐

