BLE设备三个特征值仅第一个显示,如何修复另外两个的显示问题?
问题分析与解决方案
核心问题
你的代码中最关键的错误是连续调用gatt.writeDescriptor()。Android BLE的GATT操作是串行队列式的,不支持并行执行。连续写入三个Descriptor会导致后续的写入请求被系统丢弃,最终只有第一个特征的通知配置成功,另外两个的通知并未真正开启,所以无法收到回调。
修复步骤与优化代码
1. 定义UUID常量(避免重复创建与拼写错误)
先将常用的UUID定义为类常量,提升代码可读性与维护性:
// 自定义服务UUID private static final UUID SERVICE_UUID = UUID.fromString("082b91ae-e83c-11e8-9f32-f2801f1b9fd1"); // 三个特征UUID private static final UUID CHAR1_UUID = UUID.fromString("082b9438-e83c-11e8-9f32-f2801f1b9fd1"); private static final UUID CHAR2_UUID = UUID.fromString("082b9622-e83c-11e8-9f32-f2801f1b9fd1"); private static final UUID CHAR3_UUID = UUID.fromString("082b976c-e83c-11e8-9f32-f2801f1b9fd1"); // 客户端特征配置Descriptor UUID(标准BLE通知描述符) private static final UUID CCC_DESCRIPTOR_UUID = UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"); // 保存特征引用,用于后续回调 private BluetoothGattCharacteristic mChar1, mChar2, mChar3;
2. 串行执行Descriptor写入
通过onDescriptorWrite回调确保前一个写入操作完成后,再执行下一个:
@Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if (status == BluetoothGatt.GATT_SUCCESS) { mChar1 = gatt.getService(SERVICE_UUID).getCharacteristic(CHAR1_UUID); mChar2 = gatt.getService(SERVICE_UUID).getCharacteristic(CHAR2_UUID); mChar3 = gatt.getService(SERVICE_UUID).getCharacteristic(CHAR3_UUID); if (mChar1 != null && mChar2 != null && mChar3 != null) { // 先开启第一个特征的通知并写入Descriptor gatt.setCharacteristicNotification(mChar1, true); BluetoothGattDescriptor desc1 = mChar1.getDescriptor(CCC_DESCRIPTOR_UUID); if (desc1 != null) { desc1.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(desc1); } } } } // 实现Descriptor写入完成的回调,串行处理后续写入 @Override public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { super.onDescriptorWrite(gatt, descriptor, status); if (status == BluetoothGatt.GATT_SUCCESS) { UUID charUuid = descriptor.getCharacteristic().getUuid(); if (charUuid.equals(CHAR1_UUID)) { // 第一个写入成功,处理第二个特征 gatt.setCharacteristicNotification(mChar2, true); BluetoothGattDescriptor desc2 = mChar2.getDescriptor(CCC_DESCRIPTOR_UUID); if (desc2 != null) { desc2.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(desc2); } } else if (charUuid.equals(CHAR2_UUID)) { // 第二个写入成功,处理第三个特征 gatt.setCharacteristicNotification(mChar3, true); BluetoothGattDescriptor desc3 = mChar3.getDescriptor(CCC_DESCRIPTOR_UUID); if (desc3 != null) { desc3.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); gatt.writeDescriptor(desc3); } } } else { Log.e("BLE_ERROR", "Descriptor写入失败: " + descriptor.getCharacteristic().getUuid() + ", 状态码: " + status); } }
3. 优化特征变更回调
指定明确的字符编码(避免默认编码导致的乱码/显示异常),并添加日志调试:
@Override public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) { UUID charUuid = characteristic.getUuid(); byte[] data = characteristic.getValue(); // 明确指定UTF-8编码(根据设备实际发送的编码调整) String value = new String(data, StandardCharsets.UTF_8); Log.d("BLE_DATA", "收到特征数据: " + charUuid + ", 值: " + value); runOnUiThread(() -> { if (charUuid.equals(CHAR1_UUID)) { mDataTextView1.setText(value); } else if (charUuid.equals(CHAR2_UUID)) { mDataTextView2.setText(value); } else if (charUuid.equals(CHAR3_UUID)) { mDataTextView3.setText(value); } }); }
额外检查点
- 确认BLE设备的另外两个特征支持通知属性(特征属性需包含
PROPERTY_NOTIFY或PROPERTY_INDICATE)。 - 检查设备端是否正确配置了这两个特征的广播触发逻辑,确保设备确实在发送通知。
- 确保
BluetoothGatt对象在整个连接周期内未被提前释放。
内容的提问来源于stack exchange,提问作者tachyon
相关产品推荐
相关产品推荐

