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

一、问题背景

在 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 秒恢复
  • 波形 / 数据 / 历史稳定

相关推荐
安科瑞刘鸿鹏171 天前
工业自动化系统中抗晃电保护的协同控制研究
运维·网络·嵌入式硬件·物联网
SmartRadio1 天前
进一步优化CH585M的低功耗模式
c语言·开发语言·单片机·嵌入式硬件·物联网
Jason_zhao_MR1 天前
V2G 实战:SECC GreenPHY 通信开发方案
嵌入式硬件·物联网·嵌入式·边缘计算
peixiuhui1 天前
突破边界!RK3576边缘计算网关:为工业智能注入“芯”动力
人工智能·物联网·边缘计算·rk3588·iot·rk3568·rk3576
QQ12958455041 天前
ThingsBoard - APP首页修改为手工选择组织
前端·javascript·物联网·iot
三佛科技-134163842121 天前
PL3327CE/PL3327CD/CS/CF原边调节恒流/恒压控制离线反激式开关电源芯片 典型应用电路
单片机·嵌入式硬件·物联网·智能家居
TDengine (老段)2 天前
TDengine Rust 连接器进阶指南
大数据·数据库·物联网·rust·时序数据库·tdengine·涛思数据
兆龙电子单片机设计2 天前
【STM32项目开源】STM32单片机智能语音家居控制系统
stm32·单片机·嵌入式硬件·物联网·开源·自动化
SmartRadio2 天前
MK8000(UWB射频芯片)与DW1000的协议适配
c语言·开发语言·stm32·单片机·嵌入式硬件·物联网·dw1000
F133168929572 天前
WD5030K,耐高压输出电流10A,WD5030A输出电流12A
网络·单片机·嵌入式硬件·物联网·汽车