我正在针对BLE设备实现一系列特征读取。因为readCharacteristic()
是异步执行的,并且因为我们必须等到它完成才发出另一个“读取”调用,所以我对wait()
使用了一个锁,然后在'onCharacteristicRead()
中对它进行了notify()
的锁定,以使事情再次发生。
当我在调用wait()
后使用readCharacteristic()
时,我再也没有接到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()
语句,就可以成功获取read回调。当然,这使我无法等待进一步的阅读,所以我不能不等待而前进。鉴于
readCharacteristic()
是异步的,为什么调用线程的执行与实际执行读取或调用回调的功能有关?为了使事情更加困惑,在调用
readCharacteristic()
以及调用onCharacteristicRead()
时,我展示了一个标识线程的 toast 。这两个线程具有不同的名称。我认为也许是由于某种原因在调用线程上调用了回调,但事实并非如此。那么线程在这里发生了什么? 最佳答案
这里的问题似乎是线程方面的一个模糊问题,在我的原始帖子中看不到,因为我没有张贴足够多的调用历史记录来查看它。我将解释我在这里发现的内容,以防其他人受到影响。
导致我的问题的完整通话记录如下:
discoverServices()
onServicesDiscovered()
doRead()
方法的地方readCharacteristic()
----这是发生死锁的地方,但它应该是:
onCharacteristicRead()
第一个错误:
最初,我的
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()
中进行 sleep 应该不会对BLE线程产生任何影响。 但是可以! 此更改没有影响。-----------编辑便笺--------------
发布此内容后,我真的无法合理解释为什么上述匿名线程无法正常工作。所以我再次尝试了,这次确实可以工作。不知道第一次出了什么问题,也许我忘记了在线程上调用
start()
或其他什么东西。---------结束编辑说明------------
解决方案:
最终,一时兴起,我决定在实例化我的类时创建一个背景
HandlerThread
(而不是在Thread
中旋转一个匿名的onServicesDiscovered()
)。该方法现在如下所示:public void onServicesDiscovered(final BluetoothGatt gatt, int status) {
mBackgroundHandler.post(new Runnable() {
@Override
public void run() {
doRead();
}
).start();
}
上面版本的方法有效。读取上一个特性时,对
doRead()
的调用成功地遍历了每个特性。