使用RxAndroidBLE:writeCharacteristic成功后如何退订及失败时重连?
BLE开发:writeCharacteristic成功后退订断开与失败重连方案
嘿,针对你提到的这两个BLE开发中的常见需求,我结合实际项目经验给你梳理下具体的实现思路和代码示例:
一、writeCharacteristic成功后执行退订与断开BLE连接
要完成这个流程,需要分三步来做,确保资源被正确释放,避免内存泄漏:
1. 取消特征值的通知/指示订阅
如果之前你为该特征值开启了通知或指示,首先要关闭订阅,这一步需要同时修改对应的CCCD描述符(UUID固定为00002902-0000-1000-8000-00805f9b34fb)的数值:
// 假设你已持有对应的characteristic和bluetoothGatt实例 if (targetCharacteristic != null && bluetoothGatt != null) { // 关闭特征值的通知开关 bluetoothGatt.setCharacteristicNotification(targetCharacteristic, false); // 获取CCCD描述符 BluetoothGattDescriptor cccdDescriptor = targetCharacteristic.getDescriptor( UUID.fromString("00002902-0000-1000-8000-00805f9b34fb") ); if (cccdDescriptor != null) { // 设置为禁用通知的数值 cccdDescriptor.setValue(BluetoothGattDescriptor.DISABLE_NOTIFICATION_VALUE); // 写入描述符确认退订 bluetoothGatt.writeDescriptor(cccdDescriptor); } }
2. 断开GATT连接
在确认退订后,调用disconnect()方法触发断开:
if (bluetoothGatt != null) { bluetoothGatt.disconnect(); }
3. 释放GATT资源
在BluetoothGattCallback的onConnectionStateChange回调中,当连接状态变为STATE_DISCONNECTED时,一定要调用close()释放资源:
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); if (newState == BluetoothProfile.STATE_DISCONNECTED) { // 释放GATT资源,避免内存泄漏 gatt.close(); // 这里可以添加断开后的UI提示或其他清理逻辑 } }
二、writeCharacteristic调用失败时实现重连逻辑
写入失败的原因有很多(比如连接中断、信号弱、设备无响应等),重连需要控制重试次数和延迟重试,避免无限循环:
1. 判断写入失败状态
在onCharacteristicWrite回调中捕获失败状态:
@Override public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) { super.onCharacteristicWrite(gatt, characteristic, status); if (status != BluetoothGatt.GATT_SUCCESS) { // 写入失败,触发重连逻辑 handleWriteFailure(gatt, characteristic); } }
2. 实现带重试限制的重连逻辑
这里我们设置最大重试次数和延迟时间,避免频繁重试:
private int retryTimes = 0; private static final int MAX_RETRY_LIMIT = 3; // 最大重试3次 private static final long RECONNECT_DELAY_MS = 2000; // 延迟2秒重试 private void handleWriteFailure(BluetoothGatt gatt, BluetoothGattCharacteristic failedCharacteristic) { if (retryTimes >= MAX_RETRY_LIMIT) { // 重试次数耗尽,停止重试并释放资源 retryTimes = 0; gatt.close(); // 提示用户写入失败,比如弹出Toast Toast.makeText(context, "写入失败,已重试多次,请检查设备连接", Toast.LENGTH_SHORT).show(); return; } retryTimes++; // 先断开当前无效连接 gatt.disconnect(); // 延迟后重新连接设备 new Handler(Looper.getMainLooper()).postDelayed(() -> { if (targetBluetoothDevice != null) { // 重新连接GATT,注意保持原有的回调实例 BluetoothGatt newGatt = targetBluetoothDevice.connectGatt(context, false, gattCallback); // 更新全局的bluetoothGatt实例 bluetoothGatt = newGatt; } }, RECONNECT_DELAY_MS); }
3. 重连成功后重新执行写入
在onConnectionStateChange回调中,当连接成功(STATE_CONNECTED)时,需要重新发现服务、订阅特征值,然后再次执行写入操作:
@Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); if (newState == BluetoothProfile.STATE_CONNECTED) { // 重新发现服务 gatt.discoverServices(); } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { gatt.close(); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { super.onServicesDiscovered(gatt, status); if (status == BluetoothGatt.GATT_SUCCESS) { // 重新获取目标特征值 BluetoothGattCharacteristic targetChar = gatt.getService(targetServiceUuid) .getCharacteristic(targetCharUuid); // 重新开启通知(如果需要的话) gatt.setCharacteristicNotification(targetChar, true); // 再次执行写入操作 targetChar.setValue(yourData); gatt.writeCharacteristic(targetChar); } }
注意事项
- 重连前最好检查蓝牙是否处于开启状态,避免无效操作;
- 如果是iOS平台,逻辑类似,主要通过
CBPeripheral的setNotifyValue(_:for:)取消订阅,cancelPeripheralConnection(_:)断开连接,重连则重新调用connect(_:options:); - 重试次数和延迟时间可以根据实际场景调整,比如信号差的环境可以适当延长延迟。
内容的提问来源于stack exchange,提问作者ericlee
相关产品推荐
相关产品推荐

