Android 5.1 上的多个 writeDescriptor() 调用失败

Posted

技术标签:

【中文标题】Android 5.1 上的多个 writeDescriptor() 调用失败【英文标题】:Multiple writeDescriptor() calls fail on Android 5.1 【发布时间】:2016-01-12 16:01:59 【问题描述】:

我有一个与蓝牙低功耗血糖仪通信的应用程序。

目前我的应用程序在 android 4.4.4 上运行良好,但在 5.1.1 上失败

调试发现writeDescriptor()方法多次执行失败...

使用调试器,我进入了 writeDescriptor() 方法,发现它在这一行失败:

    public boolean writeDescriptor(BluetoothGattDescriptor descriptor) 
    ...
    synchronized(mDeviceBusy) 
        if (mDeviceBusy) return false;
        mDeviceBusy = true;
    

(BluetoothGatt.java:1029)

我尝试等待 onDescriptorWrite() 回调,但它从未被调用,我还尝试等待(100 毫秒、500 毫秒和 2 秒)进行第二次写入,以查看 mDeviceBusy 变量是否已清除...两次尝试均失败...

我用谷歌搜索了这个问题,但找不到任何东西,最接近的是这个未回答的问题:Android SensorTag: writeDescriptor failed

注意:如果需要我可以附上我的代码,但它非常简单,类似于这篇文章中的代码:Android BLE notifications for Glucose

【问题讨论】:

【参考方案1】:

我发现了问题...在我的代码中,我错误地定义了 onDescriptorWrite() 回调。修复此问题后,我在编写描述符成功时设法接收回调。

解决了这个问题,我找到的解决方案是通过创建一个负责对操作进行排序的类来阻止 BTLE 操作。

我创建的类非常简单,一个单独线程上的 BlockingQueue 用于对传入操作进行排队。

BTLE 操作通过调用 writeDescriptor()、writeCharacteristic() 方法入队,一个单独的线程在空闲时开始执行操作,并且当操作完成时 gattCallback 通知线程,以便继续下一个操作。

队列类:

public BtleAsynchronousOperationThread(SensorAbstract sensor, BluetoothGatt gatt) 

    log("Creating Btle Operation thread");
    this.gatt = gatt;
    this.sensor = sensor;


public void enable() 
    log("Enabling btle command thread");
    queueReadySemaphore.release();


public void writeDescriptor(BluetoothGattDescriptor descriptor) throws BTCommunicationException 

    BtleAsynchronousCommand command = new BtleAsynchronousCommand(descriptor);
    try 
        queue.put(command);
     catch (InterruptedException e) 
        throw new BTCommunicationException("Error while writing the descriptor");
    


public void writeCharacteristic(BluetoothGattCharacteristic characteristic) throws BTCommunicationException 

    BtleAsynchronousCommand command = new BtleAsynchronousCommand(
            BtleAsynchronousCommand.CommandType.WRITE_CHARACTERISTIC, characteristic);
    try 
        queue.put(command);
     catch (InterruptedException e) 
        throw new BTCommunicationException("Error while writing the characteristic");
    


public void readCharacteristic(BluetoothGattCharacteristic characteristic) throws BTCommunicationException 

    BtleAsynchronousCommand command = new BtleAsynchronousCommand(
            BtleAsynchronousCommand.CommandType.READ_CHARACTERISTIC, characteristic);
    try 
        queue.put(command);
     catch (InterruptedException e) 
        throw new BTCommunicationException("Error while reading the characteristic");
    


public void cancel() 
    this.interrupt();


public void writeCompleted() 
    queueReadySemaphore.release();


@Override
public void run() 
    BtleAsynchronousCommand command;

    try 
        while (!(Thread.currentThread().isInterrupted())) 

            queueReadySemaphore.acquire();

            log("Waiting for BTLE command");

            command = queue.take();

            switch (command.getCommandType()) 
            case WRITE_DESCRIPTOR:
                log("Starting to write descriptor:" + command.getDescriptor().getUuid());
                if (!gatt.writeDescriptor(command.getDescriptor())) 
                    throw new BTCommunicationException("Error while writing the descriptor");
                

                break;
            case WRITE_CHARACTERISTIC:
                log("Starting to write characteristic:" + command.getCharacteristic().getUuid());
                if (!gatt.writeCharacteristic(command.getCharacteristic())) 
                    throw new BTCommunicationException("Error while writing the characteristic");
                

                break;
            case READ_CHARACTERISTIC:
                log("Starting to read characteristic:" + command.getCharacteristic().getUuid());
                if (!gatt.readCharacteristic(command.getCharacteristic())) 
                    throw new BTCommunicationException("Error while writing the characteristic");
                

                break;
            default:
                log("Unknown command received");
                break;
            
        

     catch (InterruptedException e) 
        log("Btle thread interrupted, closing.");
     catch (BTCommunicationException e) 
        log("Error while reading:" + e.getMessage());
        sensor.retry();
    

    gatt = null;
    queue = null;
    queueReadySemaphore = null;
    Thread.currentThread().interrupt();


定义蓝牙回调时:

mGattCallback = new BluetoothGattCallback() 

//Other methods can be defined around here, such as
//onConnectionStateChange(), etc

@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
                                    BluetoothGattCharacteristic characteristic) 
    onSensorCharacteristicChangedInner(gatt, characteristic);


@Override
public void onDescriptorWrite (BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status)
    log("onDescriptorWrite:"+descriptor.getUuid()+ " status:"+status);
    btleCommunicationThread.writeCompleted();


@Override
public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status) 
    log("onCharacteristicWrite:"+characteristic.getUuid()+ " status:"+status);
    btleCommunicationThread.writeCompleted();

【讨论】:

以上是关于Android 5.1 上的多个 writeDescriptor() 调用失败的主要内容,如果未能解决你的问题,请参考以下文章

无法连接到 android 5.1 上的本机本地套接字

android 5.1 WIFI图标上的感叹号及其解决办法

有啥办法可以在 Mac 上的 android studio 3.5.1 中修复这个错误

Android 上的 Xamarin WebView 显示多个实例

多个活动上的 Android 导航抽屉

如何从 Android 上的 Firebase 存储正确下载多个文件?