Android 在异步函数中未调用Kotlin回调
我正试图订阅Android API 28中可编程外围设备的多个特性 由于BLEAPI的异步特性,我需要使订阅每个特性的函数(Android 在异步函数中未调用Kotlin回调,android,kotlin,bluetooth-lowenergy,Android,Kotlin,Bluetooth Lowenergy,我正试图订阅Android API 28中可编程外围设备的多个特性 由于BLEAPI的异步特性,我需要使订阅每个特性的函数(gatt.writeDescriptor())块;否则,BLEAPI将尝试一次订阅多个特征,尽管一次只能写入一个描述符:这意味着只能订阅一个特征 阻塞是通过重写onServicesDiscoveryd回调并调用异步函数来循环并订阅特征来实现的。这被一个简单的布尔值(canContinue)阻止不幸的是,从未调用回调函数onDescriptorWrite。 请参阅下面的代码:
gatt.writeDescriptor()
)块;否则,BLEAPI将尝试一次订阅多个特征,尽管一次只能写入一个描述符:这意味着只能订阅一个特征
阻塞是通过重写onServicesDiscoveryd
回调并调用异步函数来循环并订阅特征来实现的。这被一个简单的布尔值(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()
和根据问题的建议创建一个处理程序对象都尝试了这个方法,但没有效果
如果我从同步函数调用gatt.writeDescriptor()
,就会调用回调函数,我不知道为什么它不会从异步函数调用
编辑:当(!canContinue)出现时,代码>循环实际上阻止了回调。如果我注释掉这一行,回调将触发,但我将面临与以前相同的问题。如何阻止此功能
欢迎提出任何建议!请原谅我的无知,但我非常习惯于在嵌入式系统上工作,Android对我来说是一个全新的世界
谢谢,
亚当所以我实际上自己找到了答案
while(!canContinue)代码>循环实际上阻止了回调,因为它在主线程中运行,并且优先于设置canContinue
变量所需的回调
只需从主线程中调用gatt.writeDescriptor()
函数和while
循环即可解决此问题:
val subscribe = Runnable {
gatt.writeDescriptor(descriptor)
while (!canContinue);
}
runOnUiThread(subscribe)
所以我自己就找到了答案
while(!canContinue)代码>循环实际上阻止了回调,因为它在主线程中运行,并且优先于设置canContinue
变量所需的回调
只需从主线程中调用gatt.writeDescriptor()
函数和while
循环即可解决此问题:
val subscribe = Runnable {
gatt.writeDescriptor(descriptor)
while (!canContinue);
}
runOnUiThread(subscribe)
我在评论中贴了一些注释,但我认为最好将其格式化为答案
即使您已经解决了问题,我还是建议异步运行实际的协同路由,并在其中使用
private-var-channel:channel=channel()
重写脚本编写(gatt:BluetoothGatt,描述符:BluetoothGattDescriptor,状态:Int){
GlobalScope.async{
channel.send(真)
}
}
覆盖服务发现的乐趣(gatt:BluetoothGatt,状态:Int){
GlobalScope.async{
环异步(gatt)
}
}
私有异步(gatt:BluetoothGatt){
gatt.services.forEach{gattService->
gattService.characteristics.forEach{gattChar->
CHAR_LIST.forEach{
if(gattChar.uuid.toString()包含(它)){
gatt.setCharacteristicNotification(gattChar,真实)
val descriptor=gattChar.getDescriptor(UUID.fromString(BleNamesResolver.CLIENT\u CHARACTERISTIC\u CONFIG))
descriptor.value=bluetoothgattddescriptor.ENABLE\u NOTIFICATION\u值
gatt.writeDescriptor(描述符)
channel.receive()
}
}
}
}
}
我在评论中发布了一些注释,但我认为最好将其格式化为答案
即使您已经解决了问题,我还是建议异步运行实际的协同路由,并在其中使用
private-var-channel:channel=channel()
重写脚本编写(gatt:BluetoothGatt,描述符:BluetoothGattDescriptor,状态:Int){
GlobalScope.async{
channel.send(真)
}
}
覆盖服务发现的乐趣(gatt:BluetoothGatt,状态:Int){
GlobalScope.async{
环异步(gatt)
}
}
私有异步(gatt:BluetoothGatt){
gatt.services.forEach{gattService->
gattService.characteristics.forEach{gattChar->
CHAR_LIST.forEach{
if(gattChar.uuid.toString()包含(它)){
gatt.setCharacteristicNotification(gattChar,真实)
val descriptor=gattChar.getDescriptor(UUID.fromString(BleNamesResolver.CLIENT\u CHARACTERISTIC\u CONFIG))
descriptor.value=bluetoothgattddescriptor.ENABLE\u NOTIFICATION\u值
gatt.writeDescriptor(描述符)
channel.receive()
}
}
}
}
}
您的while循环不应该在if块中吗?这意味着您只有在编写描述符时才等待。@ErnestZamelczyk您是对的,虽然这对问题本身没有影响,但移动它将有助于缓解未来的问题-谢谢,您的while循环不应该在if块中吗?这意味着您只有在编写描述符时才等待。@ErnestZamelczyk您是对的,虽然这对问题本身没有影响,但移动它将有助于缓解未来的问题-谢谢您,顺便说一句,更好的方法是在后台线程上运行协程并使用它接收通知。因此,您将(!canContinue)
替换为