BottomSheet中RecyclerView多选时如何获取选中项并通过按钮上传Firebase
问题根源
你写的Adapter其实已经把选中状态和实体类绑定了(CheckBox状态变更时会直接更新对应Item的isSelected字段),拿不到选中数据的原因完全是两个缺漏:
- Adapter没有对外提供统一的选中项获取入口
- BottomSheet和宿主的通信接口定义太弱,传不出来结构化的选中数据
具体改造步骤
1. 改造Adapter,新增选中项获取方法
你的Adapter本身持有所有条目数据的引用,直接在类内部新增一个遍历筛选选中项的公开方法即可:
// 添加到AdapterPinBottomSheet类内部 public ArrayList<ItemBottomSheetFolderList> getSelectedItems() { ArrayList<ItemBottomSheetFolderList> selectedResult = new ArrayList<>(); for (ItemBottomSheetFolderList item : array) { // 直接从实体类存储的字段读状态,完全不依赖ViewHolder的视图引用 if (item.isSelected()) { selectedResult.add(item); } } return selectedResult; }
顺带修复ViewHolder的状态错乱bug:现在你在itemView的点击回调里,先触发空的listener回调,再执行CheckBox的performClick(),会导致CheckBox状态被触发两次来回反转。直接删掉没用的listener调用,把点击逻辑简化为:
@Override public void onClick(View v) { // 点击整个条目时直接触发CheckBox状态变更,状态会自动同步到对应实体类 cbPinFolder.performClick(); }
注:原来的
RecyclerViewClickListener如果没有其他业务用途可以直接移除,避免重复触发状态变更。另外你在onBindViewHolder里先把CheckBox的监听器置空再设置状态的写法是正确的,要保留——这是避免RecyclerView复用导致状态错乱的标准操作。
2. 改造BottomSheet的通信接口
原来的BottomSheetListener只传一个空字符串,根本没法传递结构化的选中数据,直接替换接口定义:
// 替换原有BottomSheetListener接口 public interface BottomSheetListener { // 把选中的条目列表作为参数,传给实现接口的宿主页面 void onConfirmSelectedItems(ArrayList<ItemBottomSheetFolderList> selectedItems); }
3. 绑定完成按钮的交互逻辑
在BottomSheet的视图初始化阶段,拿到“完成”按钮的实例,点击时直接调用Adapter的getSelectedItems()方法拿选中数据,再通过接口传给宿主:
// 视图初始化阶段的代码 // 1. 持有Adapter实例(不要在点击事件里新建Adapter,不然拿不到已经改好的选中状态) AdapterPinBottomSheet folderAdapter = new AdapterPinBottomSheet(folderDataSource, getContext(), null); RecyclerView rvFolder = view.findViewById(R.id.rv_folder_list); rvFolder.setAdapter(folderAdapter); // 2. 绑定完成按钮的点击事件 View btnConfirm = view.findViewById(R.id.btn_confirm); btnConfirm.setOnClickListener(v -> { ArrayList<ItemBottomSheetFolderList> selectedItems = folderAdapter.getSelectedItems(); // 做空选校验 if (selectedItems.isEmpty()) { Toast.makeText(getContext(), "请至少选择一个文件夹", Toast.LENGTH_SHORT).show(); return; } // 把数据传给宿主页面,然后关闭弹窗 mListener.onConfirmSelectedItems(selectedItems); dismiss(); });
4. 宿主页面直接处理上传逻辑
Activity/Fragment实现改造后的BottomSheetListener接口,拿到选中数据后直接对接Firebase批量上传即可:
@Override public void onConfirmSelectedItems(ArrayList<ItemBottomSheetFolderList> selectedItems) { FirebaseFirestore db = FirebaseFirestore.getInstance(); // 遍历选中条目批量写入 for (ItemBottomSheetFolderList folder : selectedItems) { Map<String, Object> uploadData = new HashMap<>(); uploadData.put("folderName", folder.getFolderName()); uploadData.put("pinCount", folder.getFolderPinNum()); db.collection("user_pin_folders") .document(folder.getFolderId()) // 用实体类里的唯一标识作为文档ID .set(uploadData) .addOnSuccessListener(unused -> { // 单条上传成功处理 }) .addOnFailureListener(e -> { // 单条上传失败处理 }); } }
避坑提醒
- 千万别走歪路去通过
rvFolder.findViewHolderForAdapterPosition()逐个拿视图的CheckBox状态——RecyclerView滚动回收后,这种方式大概率会拿到空引用或者错绑的状态,从实体类读存好的选中值才是零bug的方案 - 所有选中状态的变更都要同步写到实体类的
isSelected字段,不要临时在ViewHolder里存状态,否则列表复用时会出现选中状态串到其他条目的问题
内容的提问来源于stack exchange,提问作者wizdomdiri
相关产品推荐
相关产品推荐

