使用RecyclerView-Selection库时,StaggeredGridLayoutManager布局下长按Item偶尔选中两个项的问题求助
嘿,我仔细扒了你的代码,发现导致长按偶尔选中两个项的核心问题了——你在Adapter里用position作为getItemId()的返回值,这在StaggeredGridLayoutManager的场景下绝对是个大坑!
问题根源
StaggeredGridLayoutManager在滚动、屏幕旋转、数据更新时,会重新计算Item的布局位置,同一个数据项的position很可能发生变化。而RecyclerView-Selection库的SelectionTracker依赖getItemId()返回的稳定ID来关联选中状态,如果你用position当ID,一旦布局变化,旧的position对应的ID就会指向新的数据项,自然会出现选中错位、多选的情况。
修复步骤
1. 改用数据本身的唯一ID作为ItemId
你的Note来自数据库,肯定有自己的主键id(就是areItemsTheSame里用来判断的那个id),把它作为getItemId()的返回值:
@Override public long getItemId(int position) { // 替换成Note自身的唯一ID,而不是随布局变化的position return getItem(position).getId(); }
2. 修正Bind方法的逻辑漏洞
你当前的bind方法里,只有当Item未选中时才设置标题文本,这会导致选中的Item标题消失。同时取消选中时要恢复默认背景色,不然背景会一直停留在蓝色:
public final void bind(Note note, boolean isActive) { Context context = binding.getRoot().getContext(); // 不管选中状态如何,都要设置标题 binding.noteTitle.setText(note.getTitle()); itemView.setActivated(isActive); if (isActive) { binding.noteAdapterLayout.getBackground().setTint(context.getColor(R.color.blue)); } else { // 恢复默认背景色,记得替换成你自己的默认颜色 binding.noteAdapterLayout.getBackground().setTint(context.getColor(R.color.default_note_background)); } }
3. 确认SelectionKey的正确性
你的NoteHolder.getItemDetails()里的getSelectionKey()返回的是getItemId(),现在getItemId()已经返回Note的id了,这部分不需要修改,它会自动使用正确的稳定ID来关联选中状态。
为什么这样有效?
用数据库主键作为稳定ID,无论RecyclerView的布局怎么变化(StaggeredGrid重新排列、数据刷新),每个数据项的ID都是唯一且固定的,SelectionTracker就能准确跟踪每个项的选中状态,不会再出现错位多选的情况。
内容的提问来源于stack exchange,提问作者Djanito

