Android BLE 写入特性锁定 onCharacteristicWrite/

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

主要问题:“堵塞”特征

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

我注意到的其他事情:

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

  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

                }

            }

        }

    });


大话西游666
浏览 455回答 1
1回答

呼唤远方

除了繁忙的等待(这会阻塞整个 CPU 并快速耗尽电池)之外,我看不到任何同步。有共享数据结构(可能是stopMessageThread、characteristicWriteSuccessful和messageQueue)和多个访问它们的线程。如果没有同步,就会出现竞争条件,并且堵塞可能是其表现。所以我建议采用更简单的设计,特别是没有用于发送消息的线程:private ArrayList<byte[]> messageQueue = new ArrayList<byte[]>();private boolean isSending = false;void sendMessage(byte[] message) {&nbsp; &nbsp; synchronized (this) {&nbsp; &nbsp; &nbsp; &nbsp; if (isSending) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; messageQueue.add(message);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; isSending = true;&nbsp; &nbsp; }&nbsp; &nbsp; customCharacteristic.setValue(message);&nbsp; &nbsp; bluetoothGatt.writeCharacteristic(customCharacteristic);}public void onCharacteristicWrite (BluetoothGatt gatt,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; BluetoothGattCharacteristic characteristic,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; int status) {&nbsp; &nbsp; byte[] message;&nbsp; &nbsp; synchronized (this) {&nbsp; &nbsp; &nbsp; &nbsp; if (messageQueue.size() == 0) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; isSending = false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; message = messageQueue.remove(0);&nbsp; &nbsp; }&nbsp; &nbsp; customCharacteristic.setValue(message);&nbsp; &nbsp; bluetoothGatt.writeCharacteristic(customCharacteristic);&nbsp;}该解决方案的假设是writeCharacteristic不会阻塞并且速度很快。这是一个安全的假设,因为该方法在设计上是异步的:它有一个回调,将在操作完成时调用。因此回调onCharacteristicWrite用于发送缓冲区中的下一条消息。因此,对线程的需求消失了——相关的复杂性也消失了。当从后台线程调用回调时,仍然涉及多个线程。因此,对共享数据的访问是同步的。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java