页面切换后“蓝牙连接/数据丢失”的根因与遇到的其他问题的解决办法

一、问题背景

在 Flutter App 中集成 BLE 设备(如血氧仪)后,常见问题:

  • 页面切换(Get.to / Get.back)
  • 实际蓝牙 物理连接仍存在
  • 但 UI 显示:
    • 未连接
    • 数据归零
    • 波形停止
  • 需要重新连接才能恢复

二、根因总结(核心)

BLE 状态被绑定到了页面 / Controller 生命周期

当页面 pop 或 Controller dispose:

  • characteristic 被释放
  • notify 监听被 cancel
  • Rx 状态被重置

👉 导致 "逻辑断连",而不是"物理断连"


三、核心设计原则(务必牢记)

  • BLE = 全局资源
  • 页面 / Controller = 短生命周期
  • 任何 BLE 状态,都不能放在页面层

四、最终解决方案

架构分层

复制代码
BLE Service(单例 / 常驻)
├─ connect / disconnect
├─ characteristic / notify
├─ 数据解析
├─ StreamController.broadcast
├─ 连接状态快照
└─ 最新数据快照

Controller(页面级)
├─ 只维护 UI Rx 状态
├─ 订阅 Service Stream
└─ 从 Service 恢复快照

UI Page
└─ 纯展示(Obx)

五、关键实现要点

1️⃣ BLE Service 必须是单例

dart 复制代码
class BleService {
  static final BleService _instance = BleService._internal();
  factory BleService() => _instance;
  BleService._internal();
}

2️⃣ 所有 Stream 必须 broadcast

dart 复制代码
final StreamController<T> _ctrl =
    StreamController<T>.broadcast();

原因:

  • 多页面
  • 多 controller
  • 页面销毁不影响数据源

3️⃣ 连接状态 & 快照放在 Service

dart 复制代码
bool _connected;
String _deviceId;
String _deviceName;

Stream<bool> get connectionStream;
Pc60fOxiData? latestOxi;

4️⃣ Controller onInit 无感恢复

dart 复制代码
@override
void onInit() {
  connected.value = ble.isConnected;
  deviceName.value = ble.connectedDeviceName;

  final latest = ble.latestOxi;
  if (latest != null) {
    _onData(latest);
  }

  _connSub = ble.connectionStream.listen((v) {
    connected.value = v;
  });
}

5️⃣ 页面切换不影响 BLE

  • Controller 可销毁
  • Service 常驻
  • 页面回来 → 立刻恢复 UI

六、波形"贴底直线"的真实原因

  • 协议波形值:0 ~ 127
  • Controller 误归一化为:0 ~ 1
  • UI 按 0~127 绘制

👉 数值尺度不匹配

正确做法

dart 复制代码
waveformPoints.add(p.value.toDouble());

七、自动历史记录的节流策略

目标

  • 不高频写 Hive
  • 关键变化不丢

条件

  • 时间 ≥ 5 秒
  • 或 SpO₂ ≥ ±2%
  • 或 PR ≥ ±5 bpm

八、历史记录职责划分

方法 职责
_appendHistory_o 自动记录(后台、节流)
saveCurrentToHistory 用户手动保存
_saveRecord 统一写 Hive

九、总结

页面切换后数据丢失,不是 BLE 断了,
而是 BLE 状态放错了层级。

正确做法:
BLE 常驻,Controller 可销毁,UI 只展示。


十、BLE 项目模板骨架

📁 目录结构推荐

复制代码
lib/
└─ ble/
├─ ble_service.dart        // 单例,BLE 核心
├─ ble_models.dart         // 数据模型
├─ ble_parser.dart         // 协议解析
└─ ble_constants.dart

└─ feature_x/
├─ controller.dart         // UI Controller
├─ page_home.dart
├─ page_connect.dart
└─ page_history.dart

1️⃣ BLE Service 模板(核心)

dart 复制代码
class BleService {
  static final BleService _i = BleService._internal();
  factory BleService() => _i;
  BleService._internal();

  bool _connected = false;
  String _deviceId = '';
  String _deviceName = '';

  final StreamController<bool> _connCtrl =
      StreamController<bool>.broadcast();

  bool get isConnected => _connected;
  Stream<bool> get connectionStream => _connCtrl.stream;

  Future<void> connect(...) async {
    // connect + discover + notify
    _connected = true;
    _connCtrl.add(true);
  }

  Future<void> disconnect() async {
    _connected = false;
    _connCtrl.add(false);
  }
}

2️⃣ Controller 模板(UI 层)

dart 复制代码
class FeatureController extends GetxController {
  final ble = BleService();

  final connected = false.obs;
  StreamSubscription<bool>? _connSub;

  @override
  void onInit() {
    connected.value = ble.isConnected;

    _connSub = ble.connectionStream.listen((v) {
      connected.value = v;
    });
  }

  @override
  void onClose() {
    _connSub?.cancel();
    super.onClose();
  }
}

3️⃣ UI Page 模板

dart 复制代码
@override
Widget build(BuildContext context) {
  final c = Get.find<FeatureController>();

  return Obx(() {
    if (!c.connected.value) {
      return const Text('未连接');
    }
    return const Text('已连接');
  });
}

4️⃣ 永久避免问题的 Checklist

  • BLE Service 是否单例?
  • notify 是否只在 Service?
  • Stream 是否 broadcast?
  • Controller 是否只做 UI?
  • 是否有快照(latestData)?
  • 页面切换是否不影响 BLE?

✅ 这个模版解决的问题:

  • 页面随便切,BLE 不掉
  • Controller 随便销毁,状态不丢
  • UI 秒恢复
  • 波形 / 数据 / 历史稳定

相关推荐
jkyy20149 小时前
健康座舱:健康有益赋能新能源汽车开启移动健康新场景
人工智能·物联网·汽车·健康医疗
想放学的刺客10 小时前
单片机嵌入式试题(第27期)设计可移植、可配置的外设驱动框架的关键要点
c语言·stm32·单片机·嵌入式硬件·物联网
李永奉10 小时前
杰理芯片SDK开发-ENC双麦降噪配置/调试教程
人工智能·单片机·嵌入式硬件·物联网·语音识别
Acrelhuang12 小时前
工商业用电成本高?安科瑞液冷储能一体机一站式解供能难题-安科瑞黄安南
大数据·开发语言·人工智能·物联网·安全
TDengine (老段)13 小时前
金融风控系统中的实时数据库技术实践
大数据·数据库·物联网·时序数据库·tdengine·涛思数据
柱子jason16 小时前
使用IOT-Tree Server中的RESTful模块为前端开发提供数据Api
物联网
才盛智能科技16 小时前
元K:自助KTV行业AI生态领航者
大数据·人工智能·物联网·自助ktv系统·才盛云自助ktv系统
csg110717 小时前
PIC单片机驱动BH1750光照传感器,轻松获取环境光照数据
单片机·嵌入式硬件·物联网
Acrelhuang17 小时前
工厂配电升级优选 安科瑞智能断路器安全提效又节能-安科瑞黄安南
大数据·运维·开发语言·人工智能·物联网
柱子jason17 小时前
使用IOT-Tree Server和InfluxDB对采集数据进行记录
物联网