我有一个消息线程,用于发送消息缓冲区。在特性写入下一条消息之前,一旦onCharacteristicWrite
成功,就将每条消息排队发送。特征也设置为WRITE_TYPE_NO_RESPONSE
,因此在特征写调用之间,消息缓冲区队列非常快(大约为0-7ms)。
主要问题:“卡住”的特性
大部分情况下,效果很好。当邮件数量很多时,似乎会出现此问题(可能发生的消息较少,但是在发送大量邮件时更明显)。发生的情况是将调用writeCharacteristic
,并且该特性似乎已锁定,因为onCharacteristicChanged
不再读取任何新数据,也无法访问onCharacteristicWrite
。
我注意到的其他事情:
在每个characteristicWrite
之后添加5-10ms的睡眠延迟帮助,但我不明白为什么onCharacteristicWrite
返回成功时,蓝牙GATT对象需要延迟。
有时我会在状态为8的onConnectionStateChange
中收到回调,设备超出范围。不过,这并不总是会发生。
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
),还有几个访问它们的线程。如果没有同步,则会发生竞争条件,并且jam up可能是它的体现。
因此,我建议采用更简单的设计,尤其是没有用于发送消息的线程:
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;
}
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);
}
bluetoothGatt.writeCharacteristic(customCharacteristic);
}
此解决方案中的假设是writeCharacteristic
不会阻塞并且很快。这是一个安全的假设,因为该方法在设计上是异步的:它有一个回调,该回调将在操作完成时被调用。
因此,回调onCharacteristicWrite
用于发送缓冲区中的下一条消息。因此,对线程的需求消失了,相关的复杂性也就消失了。
仍然有多个线程,因为从后台线程调用了回调。因此,对共享数据的访问是同步的。