Dart/Flutter 如何将StreamSubscription转为Future实现蓝牙连接完成后返回
问题解决方法
核心问题原因
BluetoothDevice.state是持续推送状态变化的长效流,没有特殊情况不会触发onDone回调,因此await subscription.asFuture()不会在连接完成时返回,无法达到预期的等待效果- 流监听回调内的
async异步逻辑与connect方法返回的Future没有关联,外部不会等待回调内的服务发现、_initFeatures等操作执行完成
修复方案
使用Completer手动控制Future的完成时机,在确认_initFeatures执行完成后再标记Future结束,同时增加异常处理逻辑避免Future永久挂起。
修改后完整connect方法代码:
import 'dart:async'; // 需导入Completer依赖包 Future connect(BluetoothDevice device) async { _btDevice = device; // 创建Completer手动控制Future完成状态 final completer = Completer(); StreamSubscription<BluetoothDeviceState>? subscription; subscription = device.state.listen((event) async { try { if (event == BluetoothDeviceState.disconnected) { // 设备断开状态下触发连接 await device.connect(); } else if (event == BluetoothDeviceState.connected) { // 连接成功后依次执行服务发现、功能初始化 final services = await device.discoverServices(); await _initFeatures(services); print("OK"); // 所有初始化操作完成,标记Future正常结束 if (!completer.isCompleted) { completer.complete(); } // 取消状态监听避免内存泄漏 await subscription?.cancel(); } } catch (e) { // 操作异常时标记Future失败 if (!completer.isCompleted) { completer.completeError(e); } await subscription?.cancel(); } }, onError: (e) { // 状态流本身出错的处理逻辑 if (!completer.isCompleted) { completer.completeError(e); } subscription?.cancel(); }); // 返回Completer关联的Future,等待手动触发完成 return completer.future; }
调用侧优化建议
原调用逻辑同时使用await和then存在冗余,可统一用await写法逻辑更清晰:
Future<void> _connectDevice() async { try { await widget.device.connect(widget.btDevice!); // 连接、初始化全部完成后才会执行该行后续逻辑 _initValue(); } catch (e) { print("连接失败:$e"); } }
内容的提问来源于stack exchange,提问作者Turvy
相关产品推荐
相关产品推荐

