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

Flutter应用如何监听蓝牙发送的中断信号?StreamBuilder仅状态变更时获取数据

Flutter 蓝牙中断信号实时监听方案

问题根因

你当前实现中StreamBuilder仅在状态变更时才拿到数据,核心原因有三点:

  • 未提前开启蓝牙BLE特征值的通知权限,硬件不会主动推送数据,仅在组件重建时拉取缓存的lastValue
  • 直接在build方法中引用临时的特征值value流,没有固定流引用,导致StreamBuilder无法维持稳定的订阅关系
  • 未处理流的类型问题,部分蓝牙库返回的单订阅流在组件多次重建后会中断监听

修复步骤

1. 提前初始化稳定的蓝牙监听流

在对应页面的State类中持有流和特征值引用,在initState阶段完成通知开启和流初始化,不要在build方法中临时获取流:

// 页面State内部的全局定义
late Stream<List<int>> bluetoothAlertStream;
StreamSubscription<List<int>>? _bluetoothSub;
// 对应你代码里的button_1,即传输告警信号的蓝牙特征值
BluetoothCharacteristic? alertCharacteristic;

@override
void initState() {
  super.initState();
  // 确保蓝牙设备连接、服务和特征值发现完成后调用初始化
  initBluetoothStream();
}

Future<void> initBluetoothStream() async {
  if (alertCharacteristic == null) return;
  // 必须执行:开启特征值通知,硬件才会主动上报数据
  await alertCharacteristic!.setNotifyValue(true);
  // 转为广播流,避免单订阅流因组件重建重复订阅出现异常
  bluetoothAlertStream = alertCharacteristic!.value.asBroadcastStream();
}

@override
void dispose() {
  // 页面销毁时取消订阅,防止内存泄漏
  _bluetoothSub?.cancel();
  super.dispose();
}

2. 修正StreamBuilder实现,移除冗余逻辑

你原代码中存在无效变量定义、未处理快照异常的问题,替换为以下实现:

Container(
  padding: EdgeInsets.only(left: 15),
  child: Column(
    children: <Widget>[
      StreamBuilder<List<int>>(
        // 传入提前初始化好的固定流引用
        stream: bluetoothAlertStream,
        initialData: alertCharacteristic?.lastValue,
        builder: (context, snapshot) {
          // 处理异常状态
          if (snapshot.hasError) {
            return Text(
              "蓝牙连接异常",
              style: TextStyle(
                color: Colors.red,
                fontWeight: FontWeight.w600,
                fontSize: 16.0,
              ),
            );
          }
          // 处理无数据状态
          if (!snapshot.hasData) {
            return Text(
              alertMessage,
              style: TextStyle(
                color: Colors.black,
                fontWeight: FontWeight.w600,
                fontSize: 16.0,
              ),
            );
          }
          // 解析字节数据为文本
          final rawBytes = snapshot.data!;
          final alertText = String.fromCharCodes(rawBytes);
          debugPrint("收到蓝牙上报数据:$alertText");

          return Text(
            alertText.isEmpty ? alertMessage : alertText,
            style: TextStyle(
              color: Colors.black,
              fontWeight: FontWeight.w600,
              fontSize: 16.0,
            ),
          );
        },
      ),
    ],
  ),
)

3. 注意事项

  • 若蓝牙传输的告警数据存在分包情况,需要在流转换层增加包拼接逻辑,避免单包数据截断导致告警显示不全
  • 不要在StreamBuilder的builder方法中执行流订阅、setState等副作用操作,builder仅做纯UI渲染
  • 若设备断开重连,需要重新执行setNotifyValue(true)和流初始化逻辑,恢复监听

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 07:09:16