[英]Android BLE write Characteristic locks up onCharacteristicWrite/onCharacteristicChange
I have a message thread for sending a buffer of messages.我有一个用于发送消息缓冲区的消息线程。 Each message is queued to be sent once
onCharacteristicWrite
is successful before the characteristic writes the next message.在特征写入下一条消息之前,每条消息都会排队等待
onCharacteristicWrite
成功发送。 The characeristic is also set to WRITE_TYPE_NO_RESPONSE
, so the message buffer queue is pretty fast (0-7ms approximately) between characteristic write calls. characeristic 也设置为
WRITE_TYPE_NO_RESPONSE
,因此消息缓冲区队列在特征写入调用之间非常快(大约 0-7 毫秒)。
The main issue: "jammed up" characteristic主要问题:“卡住”特性
For the most part this works great.在大多数情况下,这很有效。 The problem seems to arise when there's a large amount of messages (possibly happens with fewer message, but is more noticeable when sending lots of messages).
当有大量消息时,似乎会出现问题(可能在消息较少时发生,但在发送大量消息时更明显)。 What happens is
writeCharacteristic
will get called, and the characteristic seems to lock up, since onCharacteristicChanged
no longer reads any new data, and doesn't get to onCharacteristicWrite
.发生的事情是
writeCharacteristic
将被调用,并且该特征似乎被锁定,因为onCharacteristicChanged
不再读取任何新数据,并且不会到达onCharacteristicWrite
。
Other things I've noticed:我注意到的其他事情:
Adding a sleep delay of 5-10ms after each characteristicWrite
seems to help, but I don't understand why the Bluetooth GATT object would need a delay when onCharacteristicWrite
returns successful.在每个
characteristicWrite
写入后添加 5-10 毫秒的睡眠延迟似乎有帮助,但我不明白为什么蓝牙 GATT object 在onCharacteristicWrite
返回成功时需要延迟。
Sometimes I'll get a callback in onConnectionStateChange
with status 8, device out of range.有时我会在
onConnectionStateChange
中收到状态为 8 的回调,设备超出范围。 This doesn't always happen though.不过,这并不总是发生。
characteristicWrite
returns false;characteristicWrite
返回 false; however, it can also return true before going into the "jammed up characteristic" state described above Message Thread code:消息线程代码:
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
}
}
}
});
Aside from busy waiting, which can block an entire CPU and quickly drain the battery, I can't see any synchronization.除了忙等待会阻塞整个 CPU 并迅速耗尽电池,我看不到任何同步。 There are shared data structures (likely
stopMessageThread
, characteristicWriteSuccessful
and messageQueue
) and several threads accessing them.有共享的数据结构(可能是
stopMessageThread
、 characteristicWriteSuccessful
和messageQueue
)和几个访问它们的线程。 Without synchronization, race conditions will occur and the jam up could be a manifestation of it.如果没有同步,就会出现竞争条件,并且堵塞可能是它的一种表现。
So I propose to go with a simpler design, in particular without a thread for sending messages:所以我建议 go 设计更简单,特别是没有用于发送消息的线程:
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);
}
The assumption in this solution is that writeCharacteristic
does not block and is quick.此解决方案中的假设是
writeCharacteristic
不会阻塞并且速度很快。 That's a safe assumption as the method is asynchronous by design: it has a callback that will be called when the operation is complete.这是一个安全的假设,因为该方法在设计上是异步的:它有一个回调,将在操作完成时调用。
So the callback onCharacteristicWrite
is used to send the next message in the buffer.所以回调
onCharacteristicWrite
用于发送缓冲区中的下一条消息。 Therefore, the need for the thread goes away – and so goes the associated complexity.因此,对线程的需求消失了——相关的复杂性也消失了。
There are still several threads involved as the callback is called from a background thread.由于回调是从后台线程调用的,因此仍然涉及多个线程。 Therefore, the access to the shared data is synchronized.
因此,对共享数据的访问是同步的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.