Java Android BLE:onCharacteristicRead()似乎已被线程阻止

Java Android BLE:onCharacteristicRead()似乎已被线程阻止,java,android,multithreading,bluetooth-lowenergy,android-bluetooth,Java,Android,Multithreading,Bluetooth Lowenergy,Android Bluetooth,我正在对一个可编程设备执行一系列特征读取。因为readCharacteristic()是异步执行的,而且在发出另一个“read”调用之前,我们必须等待它完成,所以我使用了一个锁来wait(),然后在'onCharacteristicRead()中使用锁来再次运行 在调用readCharacteristic()之后,当我wait()时,我从未得到对onCharacteristicRead()的调用。如果我没有wait(),那么我确实会调用onCharacteristicRead(),并报告正确的值

我正在对一个可编程设备执行一系列特征读取。因为
readCharacteristic()
是异步执行的,而且在发出另一个“read”调用之前,我们必须等待它完成,所以我使用了一个锁来
wait()
,然后在
'onCharacteristicRead()
中使用锁来再次运行

在调用
readCharacteristic()
之后,当我
wait()
时,我从未得到对
onCharacteristicRead()
的调用。如果我没有
wait()
,那么我确实会调用
onCharacteristicRead()
,并报告正确的值

以下是相关代码,它似乎阻止了对
onCharacteristicRead()
的回调:

如果我只是删除上面的
while()
语句,我就成功地获得了读取回调。当然,这阻止了我等待做进一步的阅读,所以我不能不等待就继续前进

既然
readCharacteristic()
是异步的,为什么调用线程的执行与实际执行读取或调用回调的能力有任何关系


为了让事情更加混乱,我展示了一个toast,它在调用
readCharacteristic()
以及调用
onCharacteristicRead()
时标识线程。这两个线程有不同的名称。我认为可能是由于某种原因在调用线程上调用了回调,但事实并非如此。那么线程是怎么回事?

这里的问题似乎是一个关于线程的模糊问题,在我的原始帖子中看不到,因为我没有发布足够的调用历史记录来查看它。我会解释我在这里发现的东西,以防影响到其他人

导致我出现问题的完整通话记录如下:

public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
    doRead();
}
public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
    mBackgroundHandler.post(new Runnable() {
        @Override
        public void run() {
            doRead();
        }
    ).start();
}
  • 开始Le扫描
  • 查找我关心的设备
  • 连接到设备的GATT服务器(它返回一个GATT客户端,在这里我为所有异步通信调用提供一个BluetoothGattCallback)
  • 告诉GATT客户机
    discoverServices()
  • 片刻之后,BLE系统调用我的回调函数的
    onServicesDiscovery()
  • 现在我已经准备好开始读取特性,因为服务数据已经加载,所以这就是我在原始帖子中调用
    doRead()
    方法的地方
  • 告诉GATT客户端
    readCharacteristic()
  • 睡觉,直到阅读完毕 ----这就是死锁发生的地方,但它应该:
  • 片刻之后,BLE系统调用我的Callback的
    onCharacteristicRead()
  • 通知所有等待的线程
  • 返回到步骤7并重复
  • 第一个错误:

    最初,我的
    onServicesDiscoveryd()
    方法如下所示:

    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        doRead();
    }
    
    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        mBackgroundHandler.post(new Runnable() {
            @Override
            public void run() {
                doRead();
            }
        ).start();
    }
    
    当执行
    doRead()
    时,它将进入睡眠状态,因此会阻止执行。这会阻止回调方法完成,并且显然会阻塞整个可通信系统

    第二个错误:

    一旦我意识到上述问题,我将方法更改为:

    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                doRead();
            }
        ).start();
    }
    
    据我所知,上述版本的方法应该可以工作。我正在创建一个运行
    doRead()
    的新线程,因此睡在
    doRead()
    中不会对BLE线程产生任何影响但确实如此此更改没有影响

    -----------编辑注释--------------

    在发布这篇文章之后,我真的无法解释为什么上面的匿名帖子不起作用。所以我又试了一次,这次它确实起作用了。不确定第一次出了什么问题,可能是我忘了在线程上调用
    start()
    ,或者其他什么

    ---------结束编辑注释------------

    解决方案:

    最后,我一时兴起,决定在实例化类时创建一个后台
    HandlerThread
    (而不是在
    OnServicesDiscovery()
    中旋转一个匿名
    Thread
    )。该方法现在如下所示:

    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        doRead();
    }
    
    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        mBackgroundHandler.post(new Runnable() {
            @Override
            public void run() {
                doRead();
            }
        ).start();
    }
    

    上述版本的方法有效。调用
    doRead()
    成功地在读取前一个特征时迭代每个特征。

    我通过添加以下代码解决了这个问题

            @Override
        public void onCharacteristicWrite(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            new Thread(new Runnable() {
                @Override
                public void run() {
                    gatt.readCharacteristic(characteristic);
                }
            }).start();
        }
    

    你能提供课程的完整来源吗?我也面临着类似的问题。提前感谢。您的
    mBackgroundHandler
    是如何初始化的?注意到同样的事情了!。在writeCharacteristic()上调试和中断时,它似乎总是能工作。我想这是同步问题。