java - Android BLE 写入特性锁定 onCharacteristicWrite/onCharacteristicChange

标签 java android bluetooth-lowenergy bluetooth-gatt

我有一个用于发送消息缓冲区的消息线程。一旦 onCharacteristicWrite 成功,在特征写入下一条消息之前,每条消息都会排队等待发送。该特性也设置为WRITE_TYPE_NO_RESPONSE,因此在特性写入调用之间消息缓冲队列非常快(大约 0-7 毫秒)。

主要问题:“堵塞”特征

在大多数情况下,这非常有效。当存在大量消息时,似乎会出现此问题(可能会在消息较少时发生,但在发送大量消息时更明显)。发生的情况是 writeCharacteristic 将被调用,并且特征似乎锁定,因为 onCharacteristicChanged 不再读取任何新数据,并且无法访问 onCharacteristicWrite.

我注意到的其他事情:

  1. 在每个 characteristicWrite 之后添加 5-10ms 的 sleep 延迟似乎 有帮助,但我不明白为什么当 onCharacteristicWrite 返回成功时,蓝牙 GATT 对象需要延迟。

  2. 有时我会在 onConnectionStateChange 中收到回调,状态为 8,设备超出范围。但这并不总是发生。

  3. 有时 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用于发送缓冲区中的下一条消息。因此,对线程的需求消失了——相关的复杂性也消失了。

当从后台线程调用回调时,仍然涉及多个线程。因此,对共享数据的访问是同步的。

关于java - Android BLE 写入特性锁定 onCharacteristicWrite/onCharacteristicChange,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58332898/

相关文章:

java - 检查 youtube-api 中视频对象中是否存在嵌套键以避免 NULLPOINTEREXCEPTION

java - 如何让一个声音在Processing中播放一次?

java - 如何使用 Java 查找非字母表

java - 在 Java 中删除包含单元格 'NULL' 的 csv 格式的行

java - 实现 Vimeo 网络时出错

c# - 有没有办法在 Windows 10 中使用蓝牙 LE 库 C# 与传感器或微 Controller 进行通信?

android - 亚行错误报告 : Is there a way to reset the log?

java - 安卓。如何克隆可编辑

python - 如果在脚本或 python 上使用,蓝牙 BLE Gatttool 无法重复执行,但如果手动使用,它可以正常工作。 (树莓派 4)

android - 如何将 Android BLE BluetoothGattCallback 设置为具有状态 BluetoothProfile.STATE_CONNECTING?