使用Kotlin协程替换BLE回调函数

4
我想使用 Kotlin 协程处理 BLE 的异步回调。连接到一个 BLE 设备需要一个回调对象,就像这样: connectToBle(Context, Boolean, GattCallback) 结果会异步返回,在 GattCallback 对象的方法 onConnectionStateChanged 中实现。在文档, 我使用了 suspendCoroutine<BluetoothGatt> 来实现它。
现在,onConnectionStateChanged 返回一个 BluetoothGatt 对象,我必须将其保存为全局变量,并用于调用其他方法,例如 discoverServicesreadCharacteristicwriteCharacteristic 等等,所有这些都会在 GattCallback 对象的不同回调方法中异步返回,如 onServicesDiscovered, onCharacteristicRead, onCharacteristicWrite, 等等。
下面是使用 suspendCoroutine 的代码:
suspend fun BluetoothDevice.connectToBleDevice(
    context: Context,
    autoConnect: Boolean = false
) = suspendCoroutine<BluetoothGatt?> { cont ->

    connectGatt(context, autoConnect, object : BluetoothGattCallback() {

        override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) {
            super.onConnectionStateChange(gatt, status, newState)
            Timber.d("onConnectionStateChange: ")
            if (status != BluetoothGatt.GATT_SUCCESS) cont.resume(null) else cont.resume(gatt)
            // save gatt instance here if success
        }

        override fun onServicesDiscovered(gatt: BluetoothGatt?, status: Int) {
            super.onServicesDiscovered(gatt, status)
            if (status != BluetoothGatt.GATT_SUCCESS) cont.resume(null) else cont.resume(gatt)
            // return list of services if success
        }

        override fun onCharacteristicRead(
            gatt: BluetoothGatt?,
            characteristic: BluetoothGattCharacteristic?,
            status: Int
        ) {
            super.onCharacteristicRead(gatt, characteristic, status)
            if (status != BluetoothGatt.GATT_SUCCESS) cont.resume(null) else cont.resume(gatt)
            // return read value if success
        }
    })
}

在保存的GATT实例上调用的方法:

    fun discoverServices() {
        gatt?.discoverServices() // result received in onServicesDiscovered
    }

    fun readCharacteristic(serviceUUID: UUID, characteristicUUID: UUID) {
        gatt?.apply {
            val characteristic =
                getService(serviceUUID).getCharacteristic(characteristicUUID)
            readCharacteristic(characteristic) // result received in onCharacteristicRead
        }
    }

如果我想要编写如下的“顺序代码”:
val gatt = connectToBle(context, false, gattCallback) // suspend until onConnectionStateChanged returns successfully
discoverServices()                                    // suspend until discoverServices returns successfully
writeCharacteristic(characteristic, valueToWrite)     // suspend until value is written successfully
val valueRead = readCharacteristic(characteristic)    // suspend until the value is read successfully
disconnect()

我需要做哪些更改?除了suspendCoroutine以外,我应该使用其他什么东西吗?


也许我没有理解问题,但你具体遇到了什么问题? - tyczj
@tyczj 我期望 GATT 方法会暂停直到相应的回调函数返回,但我没有看到这种情况发生。连接方法按预期暂停,我得到了 GATT 对象,但其余的方法立即返回。 - Mahima MS
在“顺序代码”块下进行了编辑。 GATT实例将保存在与suspendCoroutine相同的类中,所有其他方法都在此实例本身上调用。onConnectionStateChange是返回connectToBle的回调,并且一旦它返回,继续执行将恢复。 如果我希望所有GATT方法都是“暂停”的,即在其相应的回调返回后返回,该怎么办? - Mahima MS
由于API的构建方式,我认为您将无法完成该操作,因为BluetoothGattCallback有多个回调函数。 - tyczj
1个回答

2
听起来 Kable 可能符合您的需求?它提供了类似于您所描述的API。
例如,您可以使用以下代码连接、读/写一个特征值,然后断开连接:
val characteristic = characteristicOf(
    service = "00001815-0000-1000-8000-00805f9b34fb",
    characteristic = "00002a56-0000-1000-8000-00805f9b34fb"
)

// todo: Use scanner (provided by Kable) to obtain `peripheral`.

peripheral.apply {
    connect()
    write(characteristic, byteArrayOf(1, 2, 3))
    val valueRead: ByteArray = read(characteristic)
    disconnect()
}

�责声�:我是Kable的贡献者,因此这有点自我宣传的��。🧑�💼

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接