Flutter司机搜索函数找到司机后未终止,仍触发无可用提示
类Uber Flutter应用司机搜索流程终止异常问题
我正在开发类Uber的Flutter应用,基于Firebase Realtime Database实现司机搜索系统:查询driversQueue节点,按FIFO规则排序后遍历司机列表,验证司机是否接受订单,找到匹配司机则调用driverFound();若遍历完无司机接受则结束搜索并通知用户。
问题:即使找到司机并执行了driverFound(),一段时间后仍会触发「无可用司机」的提示,函数未真正终止。
相关代码
void searchDriverInQueue( BuildContext context) async { if(rideRequestIdAccepted) { return ; } getFareAmount(); final databaseRef = FirebaseDatabase.instance.ref(); final driversQueueRef = databaseRef.child('driversQueue'); // Ordenar la lista de conductores por horaEntrada en orden ascendente (FIFO) driversQueueRef.orderByChild('horaEntrada').once().then((drivers) async { final snap = drivers.snapshot; if (snap == null) { Fluttertoast.showToast(msg: "There's no available"); searchDriver(context); // No hay conductores en la cola return driverFound(); } else { Map<dynamic, dynamic> driversQueueData = Map<String, dynamic>.from(snap.value as Map); print(driversQueueData); List<MapEntry<dynamic, dynamic>> driversQueueDataList = driversQueueData.entries.toList(); // Ordenar la lista según el campo "horaEntrada" driversQueueDataList.sort((a, b) { String? horaEntradaA = a.value['horaEntrada']; String? horaEntradaB = b.value['horaEntrada']; if (horaEntradaA == null || horaEntradaB == null) { if (horaEntradaA == null && horaEntradaB == null) { return 0; } else if (horaEntradaA == null) { return 1; } else { return -1; } } DateTime fechaA = DateTime.parse(horaEntradaA); DateTime fechaB = DateTime.parse(horaEntradaB); return fechaA.compareTo(fechaB); }); print(driversQueueDataList); for (MapEntry< dynamic , dynamic > entry in driversQueueDataList) { String key = entry.key; print('DRIVER ID : $key'); chosenDriverId = key; //send notification to that specific driver sendNotificationToDriverNow(chosenDriverId!); //Display Waiting Response UI from a Driver showWaitingResponseFromDriverUI(); // Esperar 10 segundos antes de continuar await Future.delayed(Duration(seconds: 10)); //Response from a Driver await FirebaseDatabase.instance.ref() .child("drivers") .child(chosenDriverId!) .child("newRideStatus") .onValue.listen((eventSnapshot) async { //1. driver has cancel the rideRequest :: Push Notification // (newRideStatus = idle) if( await eventSnapshot.snapshot.value == "idle") { //Fluttertoast.showToast(msg: "ELIMINAR MENSAJE EN PRODUCCCIÓN El conductor ha cancelado tu viaje..."); /*Future.delayed(const Duration(milliseconds: 3000), () { Fluttertoast.showToast(msg: "Por favor reinicia la app."); Navigator.pop(context); //SystemNavigator.pop(); });*/ } //2. driver has accept the rideRequest :: Push Notification // (newRideStatus = accepted) if(await eventSnapshot.snapshot.value == "accepted") { rideRequestIdAccepted = true ; //design and display ui for displaying assigned driver information showUIForAssignedDriverInfo( context ); return driverFound(); } }); } } if(!rideRequestIdAccepted) { await Future.delayed(Duration(seconds: 10)); Fluttertoast.showToast( msg: "There's not person available, sorry."); referenceRideRequest!.remove(); AssistantMethods.cancelRideRequest("Not-found", rideRequestId, context); Navigator.push( context, MaterialPageRoute(builder: (c) => MainScreen())); } }); }
driverFound () { print('found'); }
问题根源分析
- 实时监听未取消:使用
onValue.listen()创建的数据库监听流,在司机接受订单后并未被取消,return driverFound()仅退出了监听回调,无法终止外层循环和后续逻辑。 - 循环未中断:设置
rideRequestIdAccepted = true后,外层for循环仍会继续遍历剩余司机,最终走到「无可用司机」的分支。 - 异步逻辑嵌套混乱:
.then()嵌套复杂异步操作,导致流程控制失效,全局变量无法及时中断后续代码执行。
解决方案代码
void searchDriverInQueue(BuildContext context) async { if (rideRequestIdAccepted) { return; } getFareAmount(); final databaseRef = FirebaseDatabase.instance.ref(); final driversQueueRef = databaseRef.child('driversQueue'); try { // 获取司机队列并按FIFO排序 final drivers = await driversQueueRef.orderByChild('horaEntrada').once(); final snap = drivers.snapshot; if (snap == null || snap.value == null) { Fluttertoast.showToast(msg: "暂无可用司机"); searchDriver(context); driverFound(); return; } Map<dynamic, dynamic> driversQueueData = Map<String, dynamic>.from(snap.value as Map); List<MapEntry<dynamic, dynamic>> driversQueueDataList = driversQueueData.entries.toList(); // 按horaEntrada排序(FIFO) driversQueueDataList.sort((a, b) { String? horaEntradaA = a.value['horaEntrada']; String? horaEntradaB = b.value['horaEntrada']; if (horaEntradaA == null || horaEntradaB == null) { if (horaEntradaA == null && horaEntradaB == null) return 0; return horaEntradaA == null ? 1 : -1; } DateTime fechaA = DateTime.parse(horaEntradaA); DateTime fechaB = DateTime.parse(horaEntradaB); return fechaA.compareTo(fechaB); }); for (MapEntry<dynamic, dynamic> entry in driversQueueDataList) { if (rideRequestIdAccepted) break; // 已找到司机,立即中断循环 String key = entry.key; print('DRIVER ID: $key'); chosenDriverId = key; // 给司机发送通知 sendNotificationToDriverNow(chosenDriverId!); // 显示等待司机响应UI showWaitingResponseFromDriverUI(); bool driverResponded = false; StreamSubscription? statusSubscription; // 监听司机状态 statusSubscription = FirebaseDatabase.instance.ref() .child("drivers") .child(chosenDriverId!) .child("newRideStatus") .onValue.listen((eventSnapshot) { final status = eventSnapshot.snapshot.value as String?; if (status == "accepted") { rideRequestIdAccepted = true; driverResponded = true; statusSubscription?.cancel(); // 取消监听 showUIForAssignedDriverInfo(context); driverFound(); return; } else if (status == "idle") { driverResponded = true; statusSubscription?.cancel(); // 取消监听 } }); // 等待10秒,超时则处理下一个司机 await Future.delayed(const Duration(seconds: 10)); if (!driverResponded) { statusSubscription?.cancel(); // 超时取消监听 } if (rideRequestIdAccepted) break; } // 遍历完所有司机仍未找到 if (!rideRequestIdAccepted) { Fluttertoast.showToast(msg: "抱歉,暂无可用司机"); referenceRideRequest?.remove(); AssistantMethods.cancelRideRequest("Not-found", rideRequestId, context); Navigator.push(context, MaterialPageRoute(builder: (c) => MainScreen())); } } catch (e) { print("搜索司机出错: $e"); Fluttertoast.showToast(msg: "搜索司机失败,请重试"); } }
void driverFound() { print('找到可用司机'); }
关键修改点
- 将
.then()改为await,简化异步流程控制 - 给数据库监听创建
StreamSubscription,在司机响应或超时后取消订阅,避免无效回调和内存泄漏 - 在循环中增加
rideRequestIdAccepted判断,找到司机后立即中断循环 - 移除
snapshot.value前不必要的await(同步取值无需异步等待) - 增加超时逻辑,确保每个司机仅等待10秒
内容的提问来源于stack exchange,提问作者DEmmaRL
相关产品推荐
相关产品推荐

