You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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');
}

问题根源分析

  1. 实时监听未取消:使用onValue.listen()创建的数据库监听流,在司机接受订单后并未被取消,return driverFound()仅退出了监听回调,无法终止外层循环和后续逻辑。
  2. 循环未中断:设置rideRequestIdAccepted = true后,外层for循环仍会继续遍历剩余司机,最终走到「无可用司机」的分支。
  3. 异步逻辑嵌套混乱:.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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:35:36