Flutter异步函数未完成即返回:BLE扫描连接函数问题排查
Flutter Reactive Ble中scanAndConnect函数提前返回的解决办法
问题描述
我编写了一个scanAndConnect()异步函数,用于扫描BLE设备并连接到指定服务ID的设备,返回Future。问题在于,尽管在flutterReactiveBle.statusStream.listen()前使用了await,但scanAndConnect()仍会直接打印99999并返回,未等待监听逻辑执行完成。
相关代码
Future scanAndConnect(Uuid serviceId, Uuid charctId) async { StreamSubscription<BleStatus>? bleStatusStreamSubscription; StreamSubscription<DiscoveredDevice>? deviceStreamSubscription; Stream<DiscoveredDevice> stream; bleStatusStreamSubscription = await flutterReactiveBle.statusStream.listen((bleStatus) async { print("new listen ${bleStatus.toString()}"); if (bleStatus == BleStatus.ready) { await bleStatusStreamSubscription!.cancel(); connectionStatus = BLEConnectionStatus.Connecting; stream = await flutterReactiveBle.scanForDevices( withServices: [serviceId], scanMode: ScanMode.lowLatency, ); } }); print("9999999"); } // 调用代码 Future connectToDevice() async { await ble.scanAndConnect(BLE_SERVICE_UUID, BLE_CHAR_UUID); print("Statement after await in main"); setState(() { loading = false; print("Changing state to ${loading.toString()}"); }); }
Xcode输出
flutter: 9999999 flutter: Statement after await in main flutter: Changing state to false flutter: new listen BleStatus.unknown flutter: new listen BleStatus.ready
解决方案
问题根源
listen()方法返回的是StreamSubscription对象,不是可等待的Future,所以你加的await完全无效——函数会直接跳过监听逻辑,执行后续代码。要让函数等待监听内的逻辑完成,需要用Completer手动控制Future的完成时机。
修改步骤
- 导入
dart:async包(如果未导入) - 创建
Completer实例,用于标记任务完成状态 - 在监听回调中,当所有核心逻辑(比如BLE就绪、扫描启动、设备连接完成)执行完毕后,调用
completer.complete() - 最后返回
completer.future,让外部await能等待任务结束
修改后的代码示例
import 'dart:async'; Future scanAndConnect(Uuid serviceId, Uuid charctId) async { final completer = Completer<void>(); StreamSubscription<BleStatus>? bleStatusStreamSubscription; StreamSubscription<DiscoveredDevice>? deviceStreamSubscription; Stream<DiscoveredDevice>? stream; bleStatusStreamSubscription = flutterReactiveBle.statusStream.listen((bleStatus) async { print("new listen ${bleStatus.toString()}"); if (bleStatus == BleStatus.ready) { await bleStatusStreamSubscription!.cancel(); connectionStatus = BLEConnectionStatus.Connecting; stream = flutterReactiveBle.scanForDevices( withServices: [serviceId], scanMode: ScanMode.lowLatency, ); // 如果你还需要处理扫描到设备并连接的逻辑,在此处添加 // 例如监听stream并连接到目标设备,等连接成功后再调用complete // deviceStreamSubscription = stream?.listen((device) { // // 连接设备逻辑 // completer.complete(); // }); // 这里假设启动扫描即视为逻辑完成,根据你的实际需求调整时机 completer.complete(); } }, onError: (error) { // 处理错误,避免Future一直处于pending状态 completer.completeError(error); bleStatusStreamSubscription?.cancel(); }); // 等待completer标记任务完成 await completer.future; print("9999999"); // 现在这行只会在逻辑完成后打印 }
补充说明
- 如果你的业务逻辑需要等待设备连接完成,而不只是启动扫描,那需要在扫描到目标设备、完成连接后再调用
completer.complete() - 必须处理错误场景(比如BLE状态异常、扫描失败),调用
completer.completeError(),避免外部await一直阻塞
内容的提问来源于stack exchange,提问作者Salahuddin
相关产品推荐
相关产品推荐

