You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 09:00:27