android - 未在异步函数中调用 Kotlin 回调
问题描述
我正在尝试订阅 Android API 28 中 BLE 外围设备的多个特性。
由于 BLE API 的异步特性,我需要制作订阅每个特征 ( gatt.writeDescriptor()
) 块的函数;否则 BLE API 将尝试一次订阅多个特征,尽管一次只能写入一个描述符:这意味着只能订阅一个特征。
阻塞是通过重写onServicesDiscovered
回调并调用异步函数来循环和订阅特征来实现的。这被一个简单的布尔值 ( canContinue
) 阻止。不幸的是,回调函数onDescriptorWrite
永远不会被调用。
请看下面的代码:
override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
canContinue = true
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
runBlocking {
loopAsync(gatt)
}
}
private suspend fun loopAsync(gatt: BluetoothGatt) {
coroutineScope {
async {
gatt.services.forEach { gattService ->
gattService.characteristics.forEach { gattChar ->
CHAR_LIST.forEach {
if (gattChar.uuid.toString().contains(it)) {
canContinue = false
gatt.setCharacteristicNotification(gattChar, true)
val descriptor = gattChar.getDescriptor(UUID.fromString(BleNamesResolver.CLIENT_CHARACTERISTIC_CONFIG))
descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
val write = Runnable {
gatt.writeDescriptor(descriptor)
}
//private val mainHandler = Handler(Looper.getMainLooper())
//mainHandler.post(write)
//runOnUiThread(write)
gatt.writeDescriptor(descriptor)
}
while (!canContinue)
}
}
}
}
}
}
在相关帖子gatt.writeDescriptor()
中建议我在主线程中运行该函数。正如您在上面的代码中看到的那样,我尝试使用这两种方法并按照这个问题runOnUiThread()
的建议创建一个 Handler 对象都无济于事。
如果我从同步函数调用回调gatt.writeDescriptor()
,我不知道为什么它不从异步函数调用。
编辑:看来while(!canContinue);
循环实际上阻塞了回调。如果我将此行注释掉,回调会触发,但我会面临与以前相同的问题。如何阻止此功能?
欢迎任何建议!原谅我的无知,但我非常习惯于在嵌入式系统上工作,Android 对我来说是一个非常新的世界!
谢谢,亚当
解决方案
我在评论中发布了一些注释,但我认为将其格式化为答案会更好。
即使您已经解决了问题,我还是建议异步运行实际的协程,并在其中等待使用通道的写入通知
private var channel: Channel<Boolean> = Channel()
override fun onDescriptorWrite(gatt: BluetoothGatt, descriptor: BluetoothGattDescriptor, status: Int) {
GlobalScope.async {
channel.send(true)
}
}
override fun onServicesDiscovered(gatt: BluetoothGatt, status: Int) {
GlobalScope.async {
loopAsync(gatt)
}
}
private suspend fun loopAsync(gatt: BluetoothGatt) {
gatt.services.forEach { gattService ->
gattService.characteristics.forEach { gattChar ->
CHAR_LIST.forEach {
if (gattChar.uuid.toString().contains(it)) {
gatt.setCharacteristicNotification(gattChar, true)
val descriptor = gattChar.getDescriptor(UUID.fromString(BleNamesResolver.CLIENT_CHARACTERISTIC_CONFIG))
descriptor.value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE
gatt.writeDescriptor(descriptor)
channel.receive()
}
}
}
}
}
推荐阅读
- unit-testing - 在 gradle mockmvc 中执行 TestNG PUT 请求时出现“请求处理失败”
- c++ - 使用 C++、Opencv 和 GStreamer 捕获视频时出错
- c - 当值为负时不要打印消息
- php - 使用 PHP 从任何 PDF 中检索字体列表
- node.js - MongoDB聚合返回空对象而不是null
- javascript - (React/Redux) Redux 操作中的异步问题
- jsf - 如何为 primefaces 字段集容器设置自定义高度?
- javascript - 如何在循环 JavaScript 中跳过一个数字?
- c# - 绑定到集合 Xamarin 中的索引
- javascript - 暂停 foreach 循环 unitl 事件发生,之后循环继续(JavaScript)