当前位置: 首页 > news >正文

Android BLE 稳定连接管理器(Kotlin版)完整代码骨架(下篇)

在上一篇文章:

《Android 蓝牙连接不稳定怎么解决?BLE 稳定性架构设计(上篇)》

我们讲清楚了 BLE 稳定性的核心思想:

  • 连接状态机
  • GATT 操作串行化
  • 超时机制
  • 断开清理
  • 指数退避重连
  • 生命周期管理
  • 完整日志系统

这一篇我们直接落地:

实现一个 Android BLE 稳定连接管理器。

目标:

  • BLE 连接可控
  • 自动重连
  • 串行 GATT 操作
  • 支持超时
  • 支持日志
  • Kotlin 协程架构

一、整体架构设计

BLE 连接管理器整体结构:

BleManager │ ├── ConnectionStateMachine ├── OperationQueue ├── RetryPolicy ├── DeviceSession └── GattCallback

核心职责:

模块作用
BleManager统一管理 BLE
ConnectionState连接状态
OperationQueue串行执行 GATT 操作
RetryPolicy自动重连
GattCallback蓝牙回调

二、定义 BLE 连接状态

BLE 连接必须有完整状态。

sealed class BleConnectState { object Idle : BleConnectState() object Scanning : BleConnectState() object Connecting : BleConnectState() object Connected : BleConnectState() object ServiceDiscovered : BleConnectState() object Ready : BleConnectState() data class Disconnected(val reason: String) : BleConnectState() data class Failed(val code: Int) : BleConnectState() }

状态说明:

状态含义
Idle未连接
Connecting正在连接
Connected链路建立
ServiceDiscovered服务发现完成
Ready可以通信
Disconnected已断开

三、定义 GATT 操作接口

所有 GATT 操作必须串行执行

interface BleOperation { suspend fun execute(gatt: BluetoothGatt): Boolean }

例如写入操作:

class WriteOperation( private val characteristic: BluetoothGattCharacteristic, private val data: ByteArray ) : BleOperation { override suspend fun execute(gatt: BluetoothGatt): Boolean { characteristic.value = data return gatt.writeCharacteristic(characteristic) } }

四、GATT 操作队列(核心)

BLE 操作必须排队。

class OperationQueue { private val queue: ArrayDeque<suspend () -> Unit> = ArrayDeque() private var running = false fun enqueue(op: suspend () -> Unit) { queue.addLast(op) if (!running) { next() } } private fun next() { val op = queue.removeFirstOrNull() ?: run { running = false return } running = true GlobalScope.launch { op.invoke() next() } } }

这样所有 BLE 操作都会:

排队 ↓ 执行 ↓ 回调完成 ↓ 执行下一个

五、BLE Manager 核心结构

class BleManager( private val context: Context ) { private var bluetoothGatt: BluetoothGatt? = null private var currentDevice: BluetoothDevice? = null private val operationQueue = OperationQueue() private var retryCount = 0 private var manualDisconnect = false private val scope = CoroutineScope(Dispatchers.IO) }

字段说明:

变量作用
bluetoothGatt当前 GATT
currentDevice当前设备
operationQueue操作队列
retryCount重试次数
manualDisconnect是否主动断开

六、建立连接

连接入口:

fun connect(device: BluetoothDevice) { manualDisconnect = false currentDevice = device bluetoothGatt?.close() bluetoothGatt = null bluetoothGatt = device.connectGatt( context, false, gattCallback ) }

注意:

autoConnect = false

避免 Android 某些机型异常。

七、断开连接

fun disconnect() { manualDisconnect = true bluetoothGatt?.disconnect() }

断开后必须释放资源:

private fun clearGatt() { bluetoothGatt?.close() bluetoothGatt = null }

八、自动重连策略

使用指数退避算法

private fun nextRetryDelay(): Long { val delay = (1000L * (1 shl retryCount)) return minOf(delay, 15000) }

重连逻辑:

private fun scheduleReconnect() { retryCount++ val delay = nextRetryDelay() scope.launch { delay(delay) currentDevice?.let { connect(it) } } }

九、GattCallback 实现

核心 BLE 回调:

private val gattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange( gatt: BluetoothGatt, status: Int, newState: Int ) { if (newState == BluetoothProfile.STATE_CONNECTED) { log("connected") gatt.discoverServices() } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { log("disconnected status=$status") clearGatt() if (!manualDisconnect) { scheduleReconnect() } } } override fun onServicesDiscovered( gatt: BluetoothGatt, status: Int ) { if (status == BluetoothGatt.GATT_SUCCESS) { log("services discovered") } else { log("service discover failed") } } override fun onMtuChanged( gatt: BluetoothGatt, mtu: Int, status: Int ) { log("mtu changed $mtu") } }

十、MTU 协商

连接成功后可以协商 MTU。

fun requestMtu(size: Int = 247) { bluetoothGatt?.requestMtu(size) }

MTU 默认:23 。 协商后可以提升数据吞吐。

十一、开启通知

BLE 通信通常依赖 Notification。

fun enableNotification( characteristic: BluetoothGattCharacteristic ) { bluetoothGatt?.setCharacteristicNotification( characteristic, true ) val descriptor = characteristic.getDescriptor( UUID.fromString(CLIENT_CONFIG_UUID) ) descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE bluetoothGatt?.writeDescriptor(descriptor) }

十二、写数据

写入特征值:

fun write( characteristic: BluetoothGattCharacteristic, data: ByteArray ) { operationQueue.enqueue { characteristic.value = data bluetoothGatt?.writeCharacteristic(characteristic) } }

这样写入操作就会:

排队

串行执行

避免 BLE 操作冲突。

十三、超时机制(推荐)

很多 BLE API 不保证回调。

建议增加超时:

suspend fun waitResponse(timeout: Long) { withTimeoutOrNull(timeout) { suspendCancellableCoroutine<Unit> { } } ?: run { log("timeout") disconnect() } }

十四、日志系统

BLE 排查必须有日志。

private fun log(msg: String) { Log.d("BLE", msg) }

推荐日志格式:

[BLE] startScan [BLE] stopScan [BLE] connectGatt [BLE] connected [BLE] discoverServices [BLE] mtuChanged [BLE] notifyEnabled [BLE] writeCharacteristic [BLE] disconnected status=133

十五、完整流程

最终 BLE 流程:

扫描设备 ↓ 停止扫描 ↓ connectGatt ↓ 连接成功 ↓ discoverServices ↓ requestMtu ↓ enableNotification ↓ Ready ↓ 数据通信 ↓ 断线 → 自动重连

十六、工程实践建议

BLE 稳定性关键点:

设计作用
状态机控制连接阶段
操作队列保证串行
自动重连提升稳定性
超时机制防止卡死
日志系统排查问题
close释放避免蓝牙栈异常

十七、总结

Android BLE 不稳定的根本原因并不是:

蓝牙不好用。

而是很多项目:

  • 没有连接管理

  • 没有操作队列

  • 没有超时机制

  • 没有断线重连

当 BLE 架构设计完善后,稳定性会显著提升。

一句话总结:

BLE 连接不是一个 API 调用,而是一套完整的连接管理系统。

第三篇(高级篇)

《Android BLE 十大经典坑:133错误、notify失败、服务发现异常》

http://www.jsqmd.com/news/459342/

相关文章:

  • 动态规划之背包问题详解(从入门到实战)
  • Kubernetes中的网络策略(Network Policies)
  • 华为 MetaERP 已成为核电行业国产替代的核心方案,以全栈自主可控为基础,通过联合共建模式深度适配核电高安全、强管控、长周期的行业特性,已在中核、中广核等龙头企业落地标杆项目
  • SAP(以 S/4HANA 为代表)通过多组织建模、多分类账(多账套)、多币种引擎、多会计准则并行四大核心机制,在统一数据模型(ACDOCA)上实现集团化、全球化、多准则的财务核算架构
  • 3.5 数据管线、损失函数与分布式训练如何配合
  • Python 源文件默认编码是 **UTF-8**(推荐使用),如果文件包含非 ASCII 字符(如中文),无需额外声明;若需使用其他编码(如 GBK),需在文件第一行/第二行声明
  • SAP 利润中心Profit是如何实现跨法人、穿透式管理的?
  • 基于堆叠自动编码器(SAE)的人脸图像识别:Matlab 实现
  • 第10章 移动平台着色器优化实战:从简化到高级技巧
  • schoober-ai-sdk:核心ReAct 引擎的实现
  • SAP 利润中心 + 分部报告 + 集团合并 + 多准则 是怎么联动成一套集团财务架构的
  • 基于 CAN 总线的 DSP280049C 升级方案全解析
  • OpenClaw Mac本地部署保姆级教程:手把手教你“养龙虾”
  • 不是烤串故事【牛客tracker 每日一题】
  • 探索三相并网逆变器LCL逆变之控制策略与仿真实践
  • AI-Native的定义与特征
  • 华为 MetaERP 的多组织、多帐套、多币种、多会计准则核算架构,核心是元数据驱动 + 云原生微服务 + 实时核算引擎 + 分布式数据底座,实现 “交易即核算、单账套多准则、全球实时合并”
  • MATLAB Simulink 中的 BCH 编码译码:穿越 AWGN 与 BSC 信道之旅
  • 手把手教你用ZYNQ打造一款便携式多通道频谱分析仪
  • 威纶通MT8071iE触摸屏宏指令程序:清晰注释下的开机页面与产量统计功能
  • OpenClaw 本地部署教程(Windows)| GitHub 爆火 AI Agent 框架安装指南
  • Android 蓝牙连接不稳定怎么解决?BLE 稳定性架构设计(上篇)
  • Unity Scroll View内容轮播实现
  • 探索STM32 Modbus RTU 主从机源码及其实践
  • 探索雷塞HBS86H 86闭环电机驱动器方案宝藏
  • 数据库系统工程师-操作系统 I/O 管理:数据库性能优化的底层核心
  • 基于YOLOv8的人脸表情识别系统【附源码】
  • 探索Potrace算法:位图矢量化的奇妙之旅
  • 一个创业老兵关于四个终极问题的二十年纪实
  • HTML_段落与换行