Android BLE write Characteristic 锁定 onCharacteristicWrite/onCharacteristicChange
Posted
技术标签:
【中文标题】Android BLE write Characteristic 锁定 onCharacteristicWrite/onCharacteristicChange【英文标题】:Android BLE write Characteristic locks up onCharacteristicWrite/onCharacteristicChange 【发布时间】:2019-10-11 00:59:48 【问题描述】:我有一个用于发送消息缓冲区的消息线程。在特征写入下一条消息之前,每条消息都会排队等待onCharacteristicWrite
成功发送。特征也设置为WRITE_TYPE_NO_RESPONSE
,因此消息缓冲区队列在特征写入调用之间非常快(大约 0-7 毫秒)。
主要问题:“卡住”特性
在大多数情况下,这很有效。当有大量消息时,似乎会出现问题(可能在消息较少时发生,但在发送大量消息时更明显)。发生的情况是 writeCharacteristic
将被调用,并且特性似乎被锁定,因为 onCharacteristicChanged
不再读取任何新数据,也无法访问 onCharacteristicWrite
。
我注意到的其他事项:
在每个 characteristicWrite
之后添加 5-10 毫秒的睡眠延迟似乎
帮助,但我不明白为什么当onCharacteristicWrite
返回成功时蓝牙 GATT 对象需要延迟。
有时我会在onConnectionStateChange
收到回调,状态为 8,设备超出范围。不过,这并不总是发生。
characteristicWrite
返回假;但是,它也可以在进入上述“阻塞特性”状态之前返回 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。二、onCharacteristicChanged在这里起什么作用?第三,onCharacteristicWrite 不能“返回”false,因为它是一个回调。四、你的characteristicWriteSuccessful 必须是volatile。 @Emil 当然,我将更改繁忙循环,第二个,onCharacteristicChanged 从我的设备接收数据,当我收到此错误时不再这样做。第三,我的意思是“characteristicWrite”函数,而不是回调。我也会更改布尔值。 writeCharacteristic 在已经有另一个挂起的 GATT 操作时返回 false。在此写入线程运行时,您是否执行任何其他请求?对于 onCharacteristicChanged,它是您收到通知的另一个特征吗? 没有其他请求。与 oncharacteristicChanged 相同,“customCharacteristic”。 由于 android ***.com/questions/38922639/… 中的竞争条件,我建议具有两个特征。 writeCharacteristic 通常返回 false,因为您还有另一个请求待处理 android.googlesource.com/platform/frameworks/base/+/master/core/… 【参考方案1】:除了忙等待会阻塞整个 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
用于发送缓冲区中的下一条消息。因此,对线程的需求消失了——相关的复杂性也消失了。
由于回调是从后台线程调用的,因此仍然涉及多个线程。因此,对共享数据的访问是同步的。
【讨论】:
会不会是 WRITE_TYPE_NO_RESPONSE 的问题? 是的,使用 WRITE_TYPE_DEFAULT 特性不会挂起,但是在 onCharacteristicWrite 回调之间需要很长时间才能按时发送数据。时间是必不可少的。 @Codo 例如,使用 WRITE_TYPE_NO_RESPONSE 在写入后放置 Thread.sleep(10) 会有所帮助,但它比预期的要慢。 这些 cmets 是引用我的代码还是仍然引用您的原始代码?如果他们引用我的代码:你遇到了什么问题? 您的代码简化了事情,但是在使用您的代码发送带有 WRITE_TYPE_NO_RESPONSE 的消息后,我仍然遇到同样的锁定。在这种写入模式下,睡眠有助于通过所有这些,但仍会偶尔锁定。如果没有 WRITE_TYPE_NO_RESPONSE,我不会收到错误消息,但是发送消息之间的时间有点长。以上是关于Android BLE write Characteristic 锁定 onCharacteristicWrite/onCharacteristicChange的主要内容,如果未能解决你的问题,请参考以下文章
是否可以使用支持 BLE 的 Android/iPhone 作为 BLE 信标?
android BLE Peripheral 手机模拟设备发出BLE广播 BluetoothLeAdvertiser