java - Android BLE write Characteristic 锁定 onCharacteristicWrite/onCharacteristicChange
问题描述
我有一个用于发送消息缓冲区的消息线程。onCharacteristicWrite
在特征写入下一条消息之前,每条消息都会排队等待发送一次成功。characeristic 也设置为WRITE_TYPE_NO_RESPONSE
,因此消息缓冲区队列在特征写入调用之间非常快(大约 0-7 毫秒)。
主要问题:“卡住”特性
在大多数情况下,这很有效。当有大量消息时,似乎会出现问题(可能在消息较少时发生,但在发送大量消息时更明显)。发生的事情是writeCharacteristic
会被调用,并且特性似乎被锁定,因为onCharacteristicChanged
不再读取任何新数据,并且没有到达onCharacteristicWrite
.
我注意到的其他事情:
在每个之后添加 5-10ms 的睡眠延迟
characteristicWrite
似乎有帮助,但我不明白为什么蓝牙 GATT 对象在onCharacteristicWrite
返回成功时需要延迟。有时我会收到
onConnectionStateChange
状态为 8 的回调,设备超出范围。不过,这并不总是发生。- 有时
characteristicWrite
返回 false;但是,它也可以在进入上述“阻塞特性”状态之前返回 true
消息线程代码:
private boolean stopMessageThread = false;
private boolean characteristicWriteSuccessful = true;
private ArrayList<byte[]> messageQueue = new ArrayList<byte[]>();
private Thread messageThread = new Thread( new Runnable() {
private long lastTime = 0;
private int count = 0;
@Override
public void run() {
while (!Thread.currentThread().isInterrupted() && !stopMessageThread) {
if(messageQueue.size() != 0 && characteristicWriteSuccessful) {
Log.i(TAG, ""+(System.currentTimeMillis()-lastTime));
Log.i(TAG, "Queue count: "+messageQueue.size());
characteristicWriteSuccessful = false;
byte[] message = messageQueue.remove(0);
customCharacteristic.setValue(message);
boolean status = bluetoothGatt.writeCharacteristic(customCharacteristic);
Log.i(TAG, "write characteristic status "+status);
lastTime = System.currentTimeMillis();
//sleep(10); // this kinda helps but can still throw the error
}
}
}
});
解决方案
除了忙等待会阻塞整个 CPU 并迅速耗尽电池,我看不到任何同步。有共享数据结构(可能stopMessageThread
和)characteristicWriteSuccessful
和messageQueue
访问它们的多个线程。如果没有同步,就会出现竞争条件,并且堵塞可能是它的一种表现。
所以我建议采用更简单的设计,特别是没有用于发送消息的线程:
private ArrayList<byte[]> messageQueue = new ArrayList<byte[]>();
private boolean isSending = false;
void sendMessage(byte[] message) {
synchronized (this) {
if (isSending) {
messageQueue.add(message);
return;
}
isSending = true;
}
customCharacteristic.setValue(message);
bluetoothGatt.writeCharacteristic(customCharacteristic);
}
public void onCharacteristicWrite (BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic,
int status) {
byte[] message;
synchronized (this) {
if (messageQueue.size() == 0) {
isSending = false;
return;
}
message = messageQueue.remove(0);
}
customCharacteristic.setValue(message);
bluetoothGatt.writeCharacteristic(customCharacteristic);
}
此解决方案中的假设是writeCharacteristic
不会阻塞并且速度很快。这是一个安全的假设,因为该方法在设计上是异步的:它有一个回调,将在操作完成时调用。
所以回调onCharacteristicWrite
用于发送缓冲区中的下一条消息。因此,对线程的需求消失了——相关的复杂性也消失了。
由于回调是从后台线程调用的,因此仍然涉及多个线程。因此,对共享数据的访问是同步的。
推荐阅读
- slack-api - 如何获取发送 Slack 临时消息的令牌
- java - 为什么 Number 的自定义子代不继承自动装箱?
- clean-architecture - 为什么要有请求模型?
- java - JavaFX/CSS:“-fx-background-radius:10;” 搞砸了我的背景
- git - Git:合并问题
- python-3.x - 使用`os.system`调用gpg时如何传递加密消息和密码?
- bayesian - 如何分析贝叶斯分析的这个输出
- laravel-blade - 从查询字符串中获取值
- django - 从与 ForeignKey 相关的另一个模型实例创建时更新模型字段
- python - 如何在函数内编辑整数