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

Flutter使用flutter_reactive_ble时BLE连接等待及批量断连问题

循环执行BLE操作无等待问题修复

问题根因

  • onPressed回调未声明async,导致内部await逻辑不生效,for循环同步执行完毕不会等待异步操作完成
  • await与then混用导致等待逻辑混乱,无法正确等待连接、写入、断开全链路完成
  • 若你封装的connect方法未适配flutter_reactive_ble的连接状态流特性,会直接返回未完成的Future导致提前结束等待

修复代码

调整IconButton回调逻辑

IconButton(
  // 其余原有配置保持不变
  onPressed: () async { // 必须声明async才支持内部await
    for (String deviceId in deviceIdList) {
      try {
        // 串行等待单设备全链路操作完成,再执行下一个设备
        await Provider.of<BleDeviceConnector>(context, listen: false).connect(deviceId);
        await loadStuff(context);
        await Provider.of<BleDeviceConnector>(context, listen: false).disconnect(deviceId);
      } catch (e) {
        print("设备$deviceId操作失败:$e");
        // 若需要出错后中断流程,此处加break即可
      }
    }
  }
)

适配connect方法封装(针对flutter_reactive_ble原生流特性)

flutter_reactive_ble的connectToDevice返回的是连接状态流,需封装为等待连接成功才完成的Future:

import 'dart:async';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';

class BleDeviceConnector {
  final FlutterReactiveBle _ble = FlutterReactiveBle.instance;
  // 存储所有设备的连接订阅,用于后续断连
  final Map<String, StreamSubscription<ConnectionStateUpdate>> _connSubs = {};

  Future<void> connect(String deviceId) async {
    final completer = Completer<void>();
    // 重复连接前先清理旧订阅
    if (_connSubs.containsKey(deviceId)) {
      await _connSubs[deviceId]?.cancel();
      _connSubs.remove(deviceId);
    }
    final sub = _ble.connectToDevice(id: deviceId).listen(
      (state) {
        if (state.connectionStatus == DeviceConnectionStatus.connected) {
          if (!completer.isCompleted) completer.complete();
        }
      },
      onError: (e) {
        if (!completer.isCompleted) completer.completeError(e);
        _connSubs.remove(deviceId);
      },
    );
    _connSubs[deviceId] = sub;
    await completer.future;
  }
}

批量断连仅首台设备生效问题修复

问题根因

自定义的BleDeviceConnector未存储多设备的连接订阅,仅保存了单个设备的订阅实例,每次新设备连接会覆盖旧订阅,导致断连时只能拿到第一个/最后一个设备的订阅,其余设备无法正常释放连接。

修复代码

改造disconnect方法封装

Future<void> disconnect(String deviceId) async {
  if (_connSubs.containsKey(deviceId)) {
    // 取消对应设备的连接订阅,触发底层断连
    await _connSubs[deviceId]?.cancel();
    _connSubs.remove(deviceId);
  }
  // 可选:清理GATT缓存避免后续连接冲突
  await _ble.clearGattCache(deviceId);
}

批量断连调用逻辑

// 遍历已连接设备列表串行断连即可
onPressed: () async {
  for (String deviceId in connectedDeviceIdList) {
    try {
      await Provider.of<BleDeviceConnector>(context, listen: false).disconnect(deviceId);
      // 可选:添加100ms延迟,给底层BLE栈留处理时间,提升稳定性
      await Future.delayed(const Duration(milliseconds: 100));
    } catch (e) {
      print("设备$deviceId断开失败:$e");
    }
  }
}

额外注意事项

  • 所有BLE操作尽量串行执行,并发操作容易触发系统BLE栈的底层bug,导致应用无响应
  • 不需要连接设备时及时清理订阅,避免内存泄漏和后续操作冲突
  • Android平台批量操作BLE设备时,需确认已申请ACCESS_FINE_LOCATION、BLUETOOTH_CONNECT、BLUETOOTH_SCAN权限,避免权限限制导致操作失败

内容的提问来源于stack exchange,提问作者AmericanMade

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 04:57:03