【问题标题】:Android BLE: onCharacteristicRead() appears to be blocked by threadAndroid BLE:onCharacteristicRead() 似乎被线程阻止
【发布时间】:2014-10-09 00:54:34
【问题描述】:

我正在对 BLE 设备执行一系列特征读取。因为readCharacteristic() 是异步执行的,而且我们必须等到它完成才能发出另一个“读取”调用,所以我使用了wait() 的锁,然后在'onCharacteristicRead() 中使用notify() 锁来让事情重新开始。

当我在拨打readCharacteristic() 之后wait() 时,我从来没有接到过onCharacteristicRead() 的电话。如果我不wait(),那么我会接到onCharacteristicRead() 的电话并报告正确的值。

这是似乎阻止回调到onCharacteristicRead()的相关代码:

private void doRead() {
    //....internal accounting stuff up here....
    characteristic = mGatt.getService(mCurrServiceUUID).getCharacteristic(mCurrCharacteristicUUID);
    isReading = mGatt.readCharacteristic(characteristic);

    showToast("Is reading in progress? " + isReading);

    showToast("On thread: " + Thread.currentThread().getName());

    // Wait for read to complete before continuing.
    while (isReading) {
        synchronized (readLock) {
            try {
                readLock.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
    showToast("onCharacteristicRead()");
    showToast("On thread: " + Thread.currentThread().getName());

    byte[] value = characteristic.getValue();
    StringBuilder sb = new StringBuilder();
    for (byte b : value) {
        sb.append(String.format("%02X", b));
    }

    showToast("Read characteristic value: " + sb.toString());

    synchronized (readLock) {
        isReading = false;
        readLock.notifyAll();
    }
}

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

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

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

【问题讨论】:

    标签: java android multithreading bluetooth-lowenergy android-bluetooth


    【解决方案1】:

    这里的问题似乎是线程的一个模糊问题,并且在我的原始帖子中看不到,因为我没有发布足够多的通话记录来查看它。我将解释我在这里发现的内容,以防它影响到其他人。

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

    1. 开始扫描
    2. 查找我关心的设备
    3. 连接到设备的 GATT 服务器(它返回一个 GATT 客户端,我在其中为所有异步通信调用提供 BluetoothGattCallback)
    4. 告诉GATT客户端discoverServices()
    5. 片刻之后,BLE 系统调用我的回调函数onServicesDiscovered()
    6. 现在我已准备好开始读取特征,因为服务数据已加载,因此我在原帖中调用 doRead() 方法
    7. 告诉GATT客户端readCharacteristic()
    8. 进入睡眠状态直到读取完成 ---- 这是发生死锁的地方,但它应该:
    9. 片刻之后,BLE 系统调用了我的回调函数onCharacteristicRead()
    10. 通知所有等待的线程
    11. 返回第 7 步并重复

    第一个错误:

    原来我的onServicesDiscovered() 方法是这样的:

    public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
        doRead();
    }
    

    doRead() 执行时,它将进入休眠状态并因此阻塞执行。这会阻止回调方法完成,并且显然会破坏整个 BLE 通信系统。

    第二个错误:

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

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

    据我所知,上述版本的方法应该可以工作。我正在创建一个运行doRead() 的新线程,因此在doRead() 中休眠应该不会对BLE 线程产生任何影响。 但确实如此!此更改没有影响。

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

    发布后,我真的无法解释为什么上述匿名线程不起作用。所以我又试了一次,这次它确实奏效了。不知道第一次出了什么问题,也许我忘了在线程上打电话给start()什么的......

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

    解决方案:

    最后,一时兴起,我决定在我的类被实例化时创建一个背景HandlerThread(而不是在onServicesDiscovered() 中旋转一个匿名Thread)。该方法现在看起来像这样:

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

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

    【讨论】:

    • 能否提供该课程的完整源代码?我也面临着类似的问题。提前致谢。
    • 你的mBackgroundHandler是如何初始化的?
    • 注意到了同样的事情!。在 writeCharacteristic() 上调试和中断时,它似乎总是有效。我猜这是同步问题。
    【解决方案2】:

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

            @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();
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-02-03
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多