Kotlin下Firebase子集合删除指定Document时误删全部且崩溃问题
问题核心原因
- 你在
getDocumentId()方法中使用了实时快照监听器addSnapshotListener,该监听器会持续监听子集合的所有数据变更,只要数据更新就会触发回调。你点击条目调用getDocumentId()会新增一个监听器,首次回调拿到对应ID执行删除后,子集合数据变更会再次触发监听器回调,此时如果position还是之前的数值,就会删除当前快照列表对应位置的新文档,循环往复直到子集合所有文档被删完。 - 全部文档删完后
snapshot.documents是空列表,你依然执行documents[position]取数据,会触发数组索引越界异常,直接导致应用崩溃。 - 额外隐含问题:每次点击条目都会新增一个
addSnapshotListener监听器,你没有做移除处理,就算本次删除完成,监听器还会常驻内存,后续只要通知集合有变更都会触发无效回调,属于内存泄漏隐患。
修复方案
最优方案是在列表渲染阶段就缓存每个条目对应的文档ID,不需要每次点击时再查询:
- 首先在列表Adapter的数据源中,给通知数据实体类新增
documentId字段,首次拉取通知列表填充数据时,直接把每个文档的ID赋值到对应实体类中。 - 点击条目的时候直接取当前条目对应实体类的
documentId调用删除方法,直接删掉getDocumentId()方法即可:
// 列表条目点击逻辑修改 itemView.setOnClickListener { // 直接取当前条目预存的文档ID delete(currentNotificationItem.documentId) } // 原delete方法无需修改 private fun delete(docNotificationID: String) { db.collection("users").document(auth.currentUser?.email!!) .collection("notification").document(docNotificationID) .delete() }
如果一定要在点击时临时查询ID,就用*单次查询get()*替代实时监听器,只会触发一次回调不会循环执行,同时增加索引合法性判断避免崩溃:
private fun getDocumentId() { db.collection("users").document(auth.currentUser?.email!!) .collection("notification").get() // 单次查询仅回调一次 .addOnSuccessListener { snapshot -> val documents = snapshot.documents // 先判断索引是否合法,避免越界崩溃 if (position in documents.indices) { delete(documents[position].id) } } .addOnFailureListener { e -> Log.w(ContentValues.TAG, "查询失败", e) } }
内容的提问来源于stack exchange,提问作者Marwan Talal
相关产品推荐
相关产品推荐

