Java Android可恢复写入特性锁定onCharacteristicWrite/onCharacteristicChange
我有一个发送消息缓冲区的消息线程。在特征写入下一条消息之前,每条消息排队发送一次Java Android可恢复写入特性锁定onCharacteristicWrite/onCharacteristicChange,java,android,bluetooth-lowenergy,bluetooth-gatt,Java,Android,Bluetooth Lowenergy,Bluetooth Gatt,我有一个发送消息缓冲区的消息线程。在特征写入下一条消息之前,每条消息排队发送一次onCharacteristicWrite成功。characteristic也被设置为WRITE\u TYPE\u NO\u RESPONSE,因此消息缓冲队列在特征写调用之间非常快(大约0-7ms) 主要问题:“堵塞”特征 在大多数情况下,这非常有效。当存在大量消息时,问题似乎会出现(可能发生在消息较少的情况下,但在发送大量消息时更为明显)。发生的情况是,writeCharacteristic将被调用,并且该特性似
onCharacteristicWrite
成功。characteristic也被设置为WRITE\u TYPE\u NO\u RESPONSE
,因此消息缓冲队列在特征写调用之间非常快(大约0-7ms)
主要问题:“堵塞”特征
在大多数情况下,这非常有效。当存在大量消息时,问题似乎会出现(可能发生在消息较少的情况下,但在发送大量消息时更为明显)。发生的情况是,writeCharacteristic
将被调用,并且该特性似乎被锁定,因为onCharacteristicChanged
不再读取任何新数据,并且无法访问onCharacteristicWrite
我注意到的其他事情:
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
}
}
}
});
characteristicWrite
之后添加5-10ms的睡眠延迟似乎是可行的
帮助,但我不明白当onCharacteristicWrite
返回成功时,Bluetooth GATT对象为什么需要延迟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
}
}
}
});
private boolean stopMessageThread=false;
私有布尔特征WriteSuccessful=true;
private ArrayList messageQueue=new ArrayList();
私有线程messageThread=newthread(newrunnable()){
私有长lastTime=0;
私有整数计数=0;
@凌驾
公开募捐{
而(!Thread.currentThread().isInterrupted()&&!stopMessageThread){
if(messageQueue.size()!=0&&characteristicWriteSuccessful){
Log.i(标记“+(System.currentTimeMillis()-lastTime));
Log.i(标记,“队列计数:”+messageQueue.size());
characteristicWriteSuccessful=假;
字节[]消息=消息队列。删除(0);
customCharacteristic.setValue(消息);
布尔状态=bluetoothGatt.writeCharacteristic(customCharacteristic);
Log.i(标签,“写入特征状态”+状态);
lastTime=System.currentTimeMillis();
//sleep(10);//这有点帮助,但仍然会抛出错误
}
}
}
});
除了繁忙的等待(可能会阻塞整个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);
}
private ArrayList messageQueue=new ArrayList();
私有布尔isSending=false;
无效发送消息(字节[]消息){
已同步(此){
如果(正在结束){
messageQueue.add(message);
回来
}
isSending=true;
}
customCharacteristic.setValue(消息);
bluetoothGatt.书面特征(客户特征);
}
关于特征的公共无效写入(蓝牙gatt,
蓝牙特征,
int状态){
字节[]消息;
已同步(此){
if(messageQueue.size()==0){
isSending=false;
回来
}
message=messageQueue.remove(0);
}
customCharacteristic.setValue(消息);
bluetoothGatt.书面特征(客户特征);
}
此解决方案中的假设是writeCharacteristic
不会阻塞并且速度很快。这是一个安全的假设,因为该方法在设计上是异步的:它有一个回调,当操作完成时将调用该回调
因此,回调onCharacteristicWrite
用于发送缓冲区中的下一条消息。因此,对线程的需求消失了——相关的复杂性也消失了
在从后台线程调用回调时,仍涉及多个线程。因此,对共享数据的访问是同步的。除了繁忙的等待(这会阻塞整个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);
}
private ArrayList messageQueue=new ArrayList();
私有布尔isSending=false;
无效发送消息(字节[]消息){
已同步(此){
如果(正在结束){
messageQueue.add(message);
回来
}
isSending=true;
}
customCharacteristic.setValue(消息);
bluetoothGatt.书面特征(客户特征);
}
关于特征的公共无效写入(蓝牙gatt,
蓝牙特征,
int状态){
字节[]消息;
已同步(此){
if(messageQueue.size()==0){
isSending=false;
回来
}
message=messageQueue.remove(0