BLE 通道与事件回调
本文档介绍 JL OTA Android SDK 中 com.jieli.otasdk.tool.ota.ble 包的 BLE 通道实现与事件回调体系:BleManager 负责 BLE 扫描、连接、服务发现、MTU 协商与数据收发;BleEventCallbackManager 负责将底层蓝牙事件统一分发给上层注册的 BleEventCallback 回调,构成 OTA 升级过程中设备通信的完整链路。
Purpose and Scope
本页聚焦于 BLE 通道(BleManager) 与 事件回调(BleEventCallbackManager / BleEventCallback / IBleEventCallback) 两大核心职责,覆盖:
- BLE 通道的架构、生命周期与超时/重连机制;
- 11 种 BLE 事件的定义、分发机制与设计意图;
- 与通道相关的配置常量、消息码与数据模型(
BleDevice、BleScanInfo、BleConnectParam、BleSendTask); - 数据发送线程(
SendBleDataThread)与通道的协作关系; - 失败模式、并发与扩展点。
以下内容属于其他目录页,不在本页展开:
- OTA 固件升级流程本身(如
UpgradeFragment、BroadcastBoxActivity)——参见 OTA 升级相关页面; - 文件监听工具(
OtaFileObserver/OtaFileObserverHelper)——参见文件监听页面; - 全局配置(
ConfigHelper)与多设备重连(ReConnectHelper)仅在本页作为依赖提及。
Overview
在 JL OTA SDK 中,BLE 通道是与设备(如蓝牙音箱、耳机等杰理芯片设备)进行数据传输的基础设施。OTA 升级包、指令帧与应答帧全部经由 BLE GATT 通道收发,因此通道的稳定性、超时处理与事件通知质量直接决定升级成功率。
整个通道层围绕两个核心类展开:
BleManager—— 单例的 BLE 连接管理器。它封装了 AndroidBluetoothAdapter/BluetoothLeScanner/BluetoothGatt,对外提供扫描、连接、断开、MTU 协商、通知使能、数据发送等能力;内部使用主线程Handler驱动各类超时(扫描、连接、MTU、服务发现、断开等),并通过ReConnectHelper支持断线重连。BleEventCallbackManager—— 事件分发器。它继承BaseCallbackHelper<BleEventCallback>,将底层 GATT 回调与系统广播(蓝牙开关、扫描状态等)转换为 11 种语义化事件,广播给所有已注册的BleEventCallback监听者。
事件回调采用 观察者模式 + 空实现适配器(BleEventCallback):调用方只需继承 BleEventCallback 并覆写关心的回调方法,无需实现全部接口方法;BleEventCallbackManager 通过 callbackEvent(...) 统一在回调线程遍历并通知所有注册者,屏蔽了 Android BLE 回调线程切换的复杂性。
Architecture
下图展示 BLE 通道层的整体架构:应用层通过 BleManager 与 Android 系统 BLE 栈交互,BleEventCallbackManager 作为事件枢纽向上层回调分发事件,数据模型层为各环节提供载体。
flowchart TD
subgraph sg_App["应用层 (App / OTA SDK)"]
App["App / UpgradeFragment / BroadcastBoxActivity"]
end
subgraph sg_Channel["BLE 通道层 com.jieli.otasdk.tool.ota.ble"]
BM["BleManager<br/>(单例通道管理器)"]
ECM["BleEventCallbackManager<br/>(事件回调分发器)"]
SBDT["SendBleDataThread<br/>(串行发送线程)"]
RCH["ReConnectHelper<br/>(断线重连辅助)"]
BM -->|"驱动"| ECM
BM -->|"投递发送任务"| SBDT
BM -->|"断线重连"| RCH
end
subgraph sg_Callback["回调接口层 interfaces"]
IBEC["IBleEventCallback<br/>(接口)"]
BEC["BleEventCallback<br/>(空实现抽象类)"]
OWDC["OnWriteDataCallback<br/>(写数据回调)"]
IBEC <|-- BEC
BEC ..->|"注册"| ECM
OWDC ..-> SBDT
end
subgraph sg_Model["数据模型层 model"]
BD["BleDevice"]
BSI["BleScanInfo"]
BCP["BleConnectParam"]
BST["BleSendTask"]
end
subgraph sg_Android["Android 系统 BLE 栈"]
BT["BluetoothAdapter / LeScanner"]
GATT["BluetoothGatt / GattCallback"]
end
App -->|"connect / scan / send"| BM
BM -->|"系统调用"| BT
BM -->|"GATT 操作"| GATT
GATT -->|"系统回调"| BM
BM -->|"持有/使用"| BD
BM -->|"扫描结果"| BSI
BM -->|"连接参数"| BCP
SBDT -->|"任务载荷"| BST
ECM -->|"事件通知"| BEC
架构要点:
BleManager是唯一的通道入口。应用层所有 BLE 操作都汇聚到它,它同时持有BleEventCallbackManager、SendBleDataThread、ReConnectHelper,是通道层的"门面"(Facade)。- 事件流单向向上。
BluetoothGattCallback与系统BroadcastReceiver产生的原始事件,统一在BleManager内部转译为语义化事件后交给BleEventCallbackManager,再由它广播给所有注册的BleEventCallback,实现通道与业务解耦。 - 数据流向下投递。上层发送数据时,
BleManager将BleSendTask放入SendBleDataThread串行发送队列,避免并发写 GATT 特征导致的丢包。 - 数据模型是事件参数的载体。
BleDevice(连接设备状态机)、BleScanInfo(扫描附加信息)、BleConnectParam(连接参数)作为回调参数贯穿整个事件体系。
事件回调体系
回调接口层次
事件回调采用三层设计,每一层都有明确职责:
classDiagram
class IBleEventCallback {
<<interface>>
+onAdapterChange(boolean)
+onDiscoveryBleChange(boolean)
+onDiscoveryBle(BluetoothDevice, BleScanInfo)
+onBleConnection(BluetoothDevice, int)
+onBleServiceDiscovery(BluetoothDevice, int, List~BluetoothGattService~)
+onBleNotificationStatus(BluetoothDevice, UUID, UUID, int)
+onBleDataBlockChanged(BluetoothDevice, int, int)
+onBleDataNotification(BluetoothDevice, UUID, UUID, byte[])
+onBleWriteStatus(BluetoothDevice, UUID, UUID, byte[], int)
+onConnectionUpdated(BluetoothDevice, int, int, int, int)
+onSwitchBleDevice(BluetoothDevice)
}
class BleEventCallback {
<<abstract>>
+onAdapterChange(boolean)
+onDiscoveryBleChange(boolean)
+onDiscoveryBle(BluetoothDevice, BleScanInfo)
+onBleConnection(BluetoothDevice, int)
+onBleServiceDiscovery(BluetoothDevice, int, List~BluetoothGattService~)
+onBleNotificationStatus(BluetoothDevice, UUID, UUID, int)
+onBleDataBlockChanged(BluetoothDevice, int, int)
+onBleDataNotification(BluetoothDevice, UUID, UUID, byte[])
+onBleWriteStatus(BluetoothDevice, UUID, UUID, byte[], int)
+onConnectionUpdated(BluetoothDevice, int, int, int, int)
+onSwitchBleDevice(BluetoothDevice)
}
class BleEventCallbackManager {
+onAdapterChange(boolean)
+onBleConnection(BluetoothDevice, int)
+onBleDataNotification(BluetoothDevice, UUID, UUID, byte[])
+callbackEvent(Consumer~BleEventCallback~)
}
IBleEventCallback <|-- BleEventCallback
BleEventCallback <-- BleEventCallbackManager : 遍历通知
IBleEventCallback:定义全部 11 个事件的完整契约,是回调的"接口规范"。BleEventCallback:抽象类,为每个接口方法提供空实现,形成适配器模式(Adapter)。业务方继承它后只需覆写关心的方法,不必为不关心的事件写空方法,降低接入成本。BleEventCallbackManager:继承杰理基础库的BaseCallbackHelper<BleEventCallback>,内部维护注册回调集合,提供addCallback/removeCallback能力,并以callbackEvent(...)统一遍历分发。
事件分类与语义
BleEventCallbackManager 提供的 11 个事件可归为四类:
| 分类 | 事件方法 | 触发时机 | 关键参数含义 |
|---|---|---|---|
| 系统状态 | onAdapterChange(boolean bEnabled) | 手机蓝牙开关状态变化 | bEnabled:蓝牙是否开启 |
| 扫描 | onDiscoveryBleChange(boolean bStart) | BLE 扫描开始/停止 | bStart:是否开始扫描 |
| 扫描 | onDiscoveryBle(BluetoothDevice device, BleScanInfo bleScanMessage) | 扫描到设备 | bleScanMessage:扫描附加信息 |
| 连接 | onBleConnection(BluetoothDevice device, int status) | 连接状态变化 | status:BluetoothProfile.STATE_CONNECTED/DISCONNECTED |
| 连接 | onBleServiceDiscovery(BluetoothDevice device, int status, List<BluetoothGattService> services) | GATT 服务发现完成 | status:BluetoothGatt.GATT_SUCCESS 等 |
| 连接 | onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout, int status) | 连接参数(interval/latency/timeout)更新 | 对应 GATT connection priority 结果 |
| 连接 | onSwitchBleDevice(BluetoothDevice device) | 切换当前连接设备 | 多设备场景下通知上层切换 |
| 数据通道 | onBleNotificationStatus(BluetoothDevice device, UUID serviceUuid, UUID characteristicUuid, int status) | 通知特征使能/去使能结果 | 携带 service/characteristic UUID |
| 数据通道 | onBleDataBlockChanged(BluetoothDevice device, int block, int status) | 数据块(block)状态变化 | OTA 大包分块发送时的块进度 |
| 数据通道 | onBleDataNotification(BluetoothDevice device, UUID serviceUuid, UUID characteristicsUuid, byte[] data) | 收到设备主动通知(下行数据) | data:设备回传的原始字节 |
| 数据通道 | onBleWriteStatus(BluetoothDevice device, UUID serviceUuid, UUID characteristicsUuid, byte[] data, int status) | 写特征完成状态 | data:写入的字节,status:写入结果 |
分发机制:callbackEvent 统一出口
BleEventCallbackManager 的所有事件方法都遵循同一模式:将事件参数包装为 lambda,交给 callbackEvent 执行。例如:
public void onAdapterChange(boolean bEnabled) {
callbackEvent(callback -> callback.onAdapterChange(bEnabled));
}
Source: BleEventCallbackManager.java
设计意图: callbackEvent 由 BaseCallbackHelper 实现,负责三件事:
- 遍历所有已注册的
BleEventCallback; - 对每个回调执行 lambda 中的对应方法(即分发事件);
- 处理线程切换/异常隔离,避免单个回调异常影响其他监听者。
这种"管理器只做分发、不做业务"的设计,使 BleManager 在触发事件时只需一行调用(如 mCallbackManager.onBleConnection(device, status)),业务逻辑全部沉淀在回调实现侧,职责单一、易于测试。
BleEventCallback 空实现的作用
public abstract class BleEventCallback implements IBleEventCallback {
@Override
public void onAdapterChange(boolean bEnabled) {
}
@Override
public void onBleConnection(BluetoothDevice device, int status) {
}
// ...其余方法同样为空实现
}
Source: BleEventCallback.java
设计意图: 接口 + 空实现抽象类的组合是 Android 回调的经典写法。接口约束契约(防止漏实现),抽象类提供"安全默认值"(防止业务方被迫实现无关方法)。OTA SDK 上层(如 UpgradeFragment)正是继承 BleEventCallback 并覆写 onBleConnection、onBleDataNotification 等关键事件来驱动升级流程。
BleManager 通道管理
单例与初始化
BleManager 采用双重检查锁(Double-Checked Locking)单例,确保整个进程只有一个 BLE 通道实例:
public static BleManager getInstance() {
if (instance == null) {
synchronized (BleManager.class) {
if (instance == null) {
instance = new BleManager(MainApplication.getInstance());
JL_Log.w(TAG, "init", "instance : " + instance);
}
}
}
return instance;
}
Source: BleManager.java
构造函数(BleManager.java)完成四件事:
- 校验并缓存
Context,必要时同步给杰理基础库的CommonUtil(全局主上下文); - 获取
BluetoothAdapter;Android 5.0+(LOLLIPOP)获取BluetoothLeScanner; - 创建
ReConnectHelper(context, this)——断线重连辅助器,需要回调用this(即BleManager); - 调用
registerReceiver()注册系统广播接收器(如蓝牙开关变化)。
单例持有以下关键成员:
| 成员 | 类型 | 职责 |
|---|---|---|
mBleDeviceMap | Map<String, BleDevice> | 按设备地址索引的连接状态容器 |
mDiscoveredBleDevices | List<BluetoothDevice> | 扫描发现设备缓存 |
mCallbackManager | BleEventCallbackManager | 事件分发出口 |
mHandler | Handler(Looper.getMainLooper()) | 全部超时/延迟任务的驱动 |
isBleScanning | volatile boolean | 扫描状态标志(并发可见性) |
核心流程:连接 → 发现服务 → 使能通知 → 数据收发
sequenceDiagram
participant App as App / 上层
participant BM as BleManager
participant GATT as BluetoothGatt
participant ECM as BleEventCallbackManager
participant CB as BleEventCallback
App->>BM: connectBleDevice(device)
BM->>GATT: connectGatt(context, autoConnect, callback)
GATT-->>BM: onConnectionStateChange(STATE_CONNECTED)
BM->>ECM: onBleConnection(device, CONNECTED)
ECM->>CB: 遍历回调 onBleConnection(...)
BM->>GATT: discoverServices()
GATT-->>BM: onServicesDiscovered(GATT_SUCCESS, services)
BM->>ECM: onBleServiceDiscovery(device, status, services)
ECM->>CB: 遍历回调 onBleServiceDiscovery(...)
BM->>GATT: setCharacteristicNotification / 写 CCCD 描述符
GATT-->>BM: onDescriptorWrite 或 onCharacteristicWrite
BM->>ECM: onBleNotificationStatus(device, uuid, uuid, status)
Note over BM,SBDT: 通道就绪,开始数据收发
GATT-->>BM: onCharacteristicChanged(data)
BM->>ECM: onBleDataNotification(device, uuid, uuid, data)
ECM->>CB: 遍历回调 onBleDataNotification(...)
App->>BM: sendData(device, data)
BM->>SBDT: 入队 BleSendTask
SBDT->>GATT: writeCharacteristic(...)
GATT-->>BM: onCharacteristicWrite(status)
BM->>ECM: onBleWriteStatus(device, uuid, uuid, data, status)
流程要点:
- 状态机推进:每一步 GATT 操作(连接、发现服务、使能通知)完成后,
BleManager都通过mCallbackManager广播对应事件;上层依据事件驱动 OTA 状态机(如MultiOTAState系列)。 - 数据下行靠通知:设备主动上报使用
onCharacteristicChanged→onBleDataNotification;数据上行靠写:应用写入使用writeCharacteristic→onBleWriteStatus。两条路径在事件层语义分离,便于上层区分"设备应答"与"本机写入结果"。 - 发送串行化:
BleManager将写入请求封装为BleSendTask交给SendBleDataThread队列,避免多个写并发导致 GATT 层错误;发送结果通过OnWriteDataCallback回传。
主线程 Handler 超时机制
BleManager 内部所有超时都用主线程 Handler 驱动(BleManager.java)。8 个消息码分别对应一个阶段的安全网:
| 消息码 | 值 | 触发动作 |
|---|---|---|
MSG_SCAN_BLE_TIMEOUT | 0x1010 | stopLeScan() 停止扫描(12s) |
MSG_CONNECT_BLE_TIMEOUT | 0x1011 | disconnectBleDevice(device) 断开连接(40s) |
MSG_SCAN_HID_DEVICE | 0x1012 | findHidDevice() 扫描 HID 设备 |
MSG_NOTIFY_BLE_TIMEOUT | 0x1013 | disconnectBleDevice(device) 通知使能超时断开 |
MSG_CHANGE_BLE_MTU_TIMEOUT | 0x1014 | 回退 MTU 为 BluetoothConstant.BLE_MTU_MIN,按已连接处理 |
MSG_DISCOVER_SERVICES_TIMEOUT | 0x1015 | 若已有服务则强制触发 onServicesDiscovered;否则未超重连上限则标记重连并断开 |
MSG_DISCONNECT_BLE_TIMEOUT | 0x1016 | closeGatt(gatt) 并回调 STATE_DISCONNECTED |
MSG_CHECK_SYSTEM_BLE_TIMEOUT | 0x1017 | 停止系统 BLE 状态检查线程 |
例如连接超时处理:
case MSG_CONNECT_BLE_TIMEOUT: {
if (!(msg.obj instanceof BluetoothDevice)) return false;
BluetoothDevice device = (BluetoothDevice) msg.obj;
JL_Log.i(TAG, "MSG_CONNECT_BLE_TIMEOUT", "device : " + printDeviceInfo(device));
disconnectBleDevice(device);
break;
}
Source: BleManager.java
设计意图: Android BLE 的 GATT 回调在某些机型上可能"静默丢失"(系统不回调也不报错),单靠回调驱动流程会永久卡死。因此每个关键阶段都设置超时兜底:要么按成功路径补齐(如 MTU 超时回退最小值后继续)、要么清理资源并触发重连,保证通道状态机总能收敛。这也是 RECONNECT_BLE_DELAY = 2000ms 与 ReConnectHelper 存在的意义——失败后延迟重试而不是僵死。
通道常量配置
| 常量 | 值 | 说明 |
|---|---|---|
BLE_UUID_SERVICE | BluetoothConstant.UUID_SERVICE | BLE 服务 UUID(杰理协议固定值) |
BLE_UUID_WRITE | BluetoothConstant.UUID_WRITE | 写特征 UUID |
BLE_UUID_NOTIFICATION | BluetoothConstant.UUID_NOTIFICATION | 通知特征 UUID |
BLE_UUID_NOTIFICATION_DESCRIPTOR | 00002902-0000-1000-8000-00805F9B34FB | CCCD 客户端特征配置描述符(标准 GATT) |
SEND_DATA_MAX_TIMEOUT | 8000 ms | 单次写数据最大超时 |
SCAN_BLE_TIMEOUT | 12000 ms | 扫描超时 |
CONNECT_BLE_TIMEOUT | 40000 ms | 连接超时 |
CALLBACK_TIMEOUT | 6000 ms | 回调等待超时 |
RECONNECT_BLE_DELAY | 2000 ms | 断线重连延迟 |
MIN_CONNECT_TIME | 8000 ms | 最小连接保持时间 |
UUID 常量直接复用杰理基础库 BluetoothConstant(BleManager.java),确保与设备端固件协议严格一致;CCCD 描述符 UUID 0x2902 是 BLE 标准值,用于使能 notification。
使用示例
以下示例均从 SDK 源码中提取。
示例 1:注册事件回调并监听连接与数据
上层(如 UpgradeFragment)继承 BleEventCallback,只覆写关心的连接与数据事件,然后注册到通道:
public abstract class BleEventCallback implements IBleEventCallback {
@Override
public void onBleConnection(BluetoothDevice device, int status) {
// 连接状态变化:status 为 STATE_CONNECTED / STATE_DISCONNECTED
}
@Override
public void onBleDataNotification(BluetoothDevice device, UUID serviceUuid,
UUID characteristicsUuid, byte[] data) {
// 设备主动上报的数据(OTA 应答帧)
}
// 其余方法默认空实现,可选择性覆写
}
Source: BleEventCallback.java
示例 2:获取通道单例
BleManager manager = BleManager.getInstance();
// 之后可调用扫描、连接、发送等通道方法
Source: BleManager.java
示例 3:事件分发器的触发模式(通道内部)
BleManager 在底层 GATT 回调中调用分发器,完成事件转译:
public void onBleConnection(BluetoothDevice device, int status) {
callbackEvent(callback -> callback.onBleConnection(device, status));
}
public void onBleDataNotification(BluetoothDevice device, UUID serviceUuid,
UUID characteristicsUuid, byte[] data) {
callbackEvent(callback -> callback.onBleDataNotification(device, serviceUuid, characteristicsUuid, data));
}
public void onBleWriteStatus(BluetoothDevice device, UUID serviceUuid,
UUID characteristicsUuid, byte[] data, int status) {
callbackEvent(callback -> callback.onBleWriteStatus(device, serviceUuid, characteristicsUuid, data, status));
}
Source: BleEventCallbackManager.java
说明: 三个示例分别展示了"回调定义侧"、"通道入口侧"与"分发触发侧",覆盖事件回调的完整闭环。实际接入时,业务方只需做示例 1(继承 + 注册),通道内部机制无需改动。
API Reference
BleEventCallbackManager(事件分发器)
继承 BaseCallbackHelper<BleEventCallback>,全部方法为 void,无返回值、不抛受检异常。参数含义见"事件分类与语义"表。
| 方法签名 | 说明 |
|---|---|
onAdapterChange(boolean bEnabled) | 系统蓝牙开关变化 |
onDiscoveryBleChange(boolean bStart) | 扫描开始/结束 |
onDiscoveryBle(BluetoothDevice device, BleScanInfo bleScanMessage) | 扫描到设备 |
onBleConnection(BluetoothDevice device, int status) | 连接状态变化 |
onBleServiceDiscovery(BluetoothDevice device, int status, List<BluetoothGattService> services) | 服务发现完成 |
onBleNotificationStatus(BluetoothDevice device, UUID serviceUuid, UUID characteristicUuid, int status) | 通知使能结果 |
onBleDataBlockChanged(BluetoothDevice device, int block, int status) | 数据块进度变化 |
onBleDataNotification(BluetoothDevice device, UUID serviceUuid, UUID characteristicsUuid, byte[] data) | 收到设备通知数据 |
onBleWriteStatus(BluetoothDevice device, UUID serviceUuid, UUID characteristicsUuid, byte[] data, int status) | 写特征完成 |
onConnectionUpdated(BluetoothDevice device, int interval, int latency, int timeout, int status) | 连接参数更新 |
onSwitchBleDevice(BluetoothDevice device) | 切换当前设备 |
BleEventCallback(回调适配基类)
- 抽象类,实现
IBleEventCallback的全部 11 个方法为空实现。 - 继承方式:
class MyCallback extends BleEventCallback { ... }。 - 设计意图:空实现使业务方与通道解耦——未覆写的事件自动忽略,覆写的事件通过
BleEventCallbackManager在触发时被调用。
BleManager(通道管理器,部分方法)
| 方法 | 说明 |
|---|---|
static BleManager getInstance() | 获取进程级单例(双重检查锁) |
void registerCallback(BleEventCallback cb) / void unregisterCallback(...) | 注册/注销事件回调(由 BleEventCallbackManager 透出) |
connectBleDevice(BluetoothDevice device) | 发起 GATT 连接(40s 超时兜底) |
disconnectBleDevice(BluetoothDevice device) | 断开连接(带超时强制 closeGatt) |
sendData(device, byte[] data, OnWriteDataCallback cb) | 封装 BleSendTask 入队串行发送(8s 超时) |
说明:
BleManager共有 1200+ 行(BleManager.java),本页仅列出与"通道与事件回调"主题直接相关的入口。扫描(startLeScan/stopLeScan)、MTU 协商(changeMtu)、通知使能(notifyCharacteristic)等完整方法清单请直接查阅源码。
相关接口与模型
IBleOp:通道操作能力接口(连接、断开、发送等抽象)。OnWriteDataCallback:写数据完成回调,供SendBleDataThread回传写结果。OnThreadStateListener:发送线程状态监听。BleDevice:连接设备状态机(GATT 引用、MTU、重连计数、isOverReconnectLimit())。BleScanInfo:扫描附加信息(如广播数据解析结果)。BleConnectParam:连接参数(扫描/连接/重连配置)。BleSendTask:发送任务封装(设备、数据、回调)。
失败模式、边界情况与并发
失败模式与兜底策略
| 失败场景 | 表现 | 兜底策略 |
|---|---|---|
| 扫描无结果 | 12s 内无设备 | MSG_SCAN_BLE_TIMEOUT 强制 stopLeScan(),避免资源泄漏 |
| 连接超时 | 40s 未连上(GATT 回调静默丢失) | MSG_CONNECT_BLE_TIMEOUT 调用 disconnectBleDevice 清理,触发 ReConnectHelper 重连 |
| 服务发现超时 | discoverServices 无回调 | 若有已缓存服务则强制走 onServicesDiscovered(GATT_SUCCESS);否则未超重连上限则标记重连并断开 |
| MTU 协商超时 | requestMtu 无回调 | 回退 BLE_MTU_MIN 并按已连接继续,保证通道不因 MTU 失败而卡死 |
| 通知使能超时 | 写 CCCD 无回调 | MSG_NOTIFY_BLE_TIMEOUT 断开设备 |
| 写数据超时 | 单次写 8s 无结果 | SEND_DATA_MAX_TIMEOUT 由发送线程判定失败并回调 OnWriteDataCallback |
| 系统蓝牙异常 | 蓝牙被关闭/驱动异常 | onAdapterChange(false) 通知上层,CheckSystemBleThread + MSG_CHECK_SYSTEM_BLE_TIMEOUT 兜底 |
设计意图: 通道层把"系统回调不可靠"当作默认前提,每一阶段都布置超时安全网(安全网清单见"主线程 Handler 超时机制")。这显著提升了 OTA 长任务的健壮性——升级过程动辄数分钟,任何一步卡死都可能导致固件半写状态。
并发与线程模型
- 超时与调度全部收敛在主线程
Handler:mHandler绑定Looper.getMainLooper(),消息按序执行,避免多线程操作 GATT 的竞态。 volatile状态标志:instance、isBleScanning等跨线程读写的字段用volatile保证可见性;单例初始化用synchronized双重检查。- 发送队列串行化:
SendBleDataThread是独立的发送线程,BleSendTask按序消费,保证同一设备上 GATT 写操作不并发——这是 Android BLE 规范(单连接单写)的硬性要求。 - 集合的线程安全注意:
mBleDeviceMap(HashMap)与mDiscoveredBleDevices(ArrayList)为普通集合,主要在 GATT 回调线程(Binder线程池)与主线程间访问,实际使用中依赖"主线程 Handler 串行化"约束访问时机;扩展时若新增跨线程读写,需自行加锁。
边界情况
- MTU 回退路径:MTU 协商失败不中断连接,回退
BLE_MTU_MIN继续走已连接流程,保证低速但可用的通道。 - 重连上限:
BleDevice.isOverReconnectLimit()决定服务发现失败后是否继续重连,防止无限重连消耗资源。 - 多设备切换:
onSwitchBleDevice事件支持多设备场景下的通道切换通知,mBleDeviceMap按地址索引管理多设备状态。
性能与运维注意事项
- 扫描超时 12s 是"建议最小扫描时长"(源码注释),实际使用应结合 UI 交互控制扫描窗口,避免长时间扫描耗电。
- 写数据 8s 超时 对 OTA 大包分块传输是硬约束;若单包写入频繁超时,应检查 MTU 与设备端应答节奏,而不是盲目提高超时。
- 日志:
BleManager全程使用JL_Log(TAG =BleManager),且printDeviceInfo打印设备关键信息,线上排查连接/超时问题可据此定位。 - 主线程安全网消息通过
Handler.removeCallbacks与sendMessageDelayed管理,需注意在断开连接后及时移除未触发的超时消息,避免"幽灵回调"。
扩展点
- 自定义业务回调:继承
BleEventCallback并注册到BleEventCallbackManager,即可在不动通道代码的前提下订阅任意事件组合(观察者模式的天然扩展性)。 - 发送结果回调:
OnWriteDataCallback允许上层感知每次写的成败,可用于实现自定义重传/流控策略。 - 重连策略:
ReConnectHelper为可替换的协作组件,重连延迟RECONNECT_BLE_DELAY、重连上限等策略可通过其实现调整。 - 接口抽象:
IBleOp/OnThreadStateListener将操作与线程状态抽象为接口,便于单元测试替身(mock)与未来替换底层 BLE 实现(如迁移到 Jetpack Bluetooth)。
测试
- 通道层依赖 Android 系统 BLE 栈,核心逻辑(单例、超时消息、事件分发)适合以 mock
BluetoothGatt/BluetoothDevice进行单元测试。 BleEventCallbackManager的分发逻辑可完全脱离蓝牙硬件测试:注册若干回调后逐个触发 11 个事件方法,断言各回调被正确调用——这验证了"分发与业务解耦"的可测性设计。- 事件回调的"空实现抽象类"使测试子类只需覆写被测事件,大幅降低测试样板代码。
Related Links
- BleEventCallbackManager.java — 事件分发器源码
- BleManager.java — BLE 通道管理器源码
- BleEventCallback.java — 回调适配基类
- IBleEventCallback.java — 回调接口定义
interfaces/IBleOp.java、interfaces/OnWriteDataCallback.java、interfaces/OnThreadStateListener.java— 通道操作与发送回调接口model/BleDevice.java、model/BleScanInfo.java、model/BleConnectParam.java、model/BleSendTask.java— 通道数据模型SendBleDataThread.java— 串行发送线程- 相关页面:OTA 升级流程、文件监听(
OtaFileObserver)、全局配置(ConfigHelper)