GeoQuery.removeAllListeners无效致Firebase重复数据问题
问题原因
数据库出现重复数据的核心原因是监听器移除逻辑的作用对象错误,没有真正清理掉旧查询的监听,导致多轮扩大半径生成的查询同时在后台运行,重复触发写入逻辑:
- 每次进入
getTheClosestDriver()方法时,你都会通过geoFire.queryAtLocation()创建一个全新的GeoQuery实例,再把这个新实例赋值给成员变量geoQuery - 紧接着调用
geoQuery.removeAllListeners()时,操作的是刚创建的、还没绑定任何监听器的新实例,上一轮递归生成的旧GeoQuery实例的引用已经被新值覆盖,你根本无法访问到旧实例,上面绑定的监听器完全没有被移除 - 所有没被清理的旧半径查询会持续在后台监听位置变化,只要匹配到符合条件的司机就会触发
onKeyEntered回调,重复执行写入司机关联信息的逻辑,最终导致数据库出现重复数据 - 额外隐患:成功找到司机后,你也没有主动移除当前GeoQuery的监听器,查询会一直保持运行,白白消耗资源,还可能在后续流程中触发不必要的回调。
修复方案
调整代码执行顺序,保证创建新查询前先清理旧查询的监听器,找到司机后立刻终止查询,修复后的核心代码如下:
private GeoQuery geoQuery; private void getTheClosestDriver() { // 优先清理上一轮残留的旧查询监听器,再创建新查询 if (geoQuery != null) { geoQuery.removeAllListeners(); } GeoFire geoFire = new GeoFire(driverAvailableRef); geoQuery = geoFire.queryAtLocation(new GeoLocation(customerPickUpLocation.latitude,customerPickUpLocation.longitude),radius); geoQuery.addGeoQueryEventListener(new GeoQueryEventListener() { @Override public void onKeyEntered(String key, GeoLocation location) { if (!driverFound && requestType){ driverFound = true; // 找到司机后第一时间移除所有监听,终止查询,避免后续重复触发 geoQuery.removeAllListeners(); driverFoundID = key; driverRef = FirebaseDatabase.getInstance().getReference().child("Users").child("Drivers").child(driverFoundID); HashMap driverMap = new HashMap(); driverMap.put("customerFoundId",customerID); driverRef.updateChildren(driverMap); gettingTheDriverLocation(); } } @Override public void onKeyExited(String key) {} @Override public void onKeyMoved(String key, GeoLocation location) {} @Override public void onGeoQueryReady() { if (!driverFound){ radius = radius + 1; getTheClosestDriver(); bookARide.setText("Searching For a Driver Location"); } } @Override public void onGeoQueryError(DatabaseError error) { Toast.makeText(CustomerMapsActivity.this,error.getMessage(),Toast.LENGTH_LONG).show(); } }); }
额外优化建议
- 用户取消叫车、退出当前页面时,也要主动调用
geoQuery.removeAllListeners()清理监听,避免内存泄漏和后台无效查询 - 给搜索半径设置合理上限,比如最大不超过10公里,避免无限递归扩大搜索范围造成不必要的性能消耗
内容的提问来源于stack exchange,提问作者Ukeme Elijah
相关产品推荐
相关产品推荐

