android - 使用 Kotlin 协程替换 BLE 回调

标签 android kotlin bluetooth-lowenergy kotlin-coroutines

我想使用 Kotlin 的协程来处理 BLE 的异步回调。连接到 BLE 设备需要一个回调对象,例如:connectToBle(Context, Boolean, GattCallback)结果在方法onConnectionStateChanged中异步返回GattCallback 对象。我用了suspendCoroutine<BluetoothGatt>按照文档 here 中的详细说明实现此操作.
现在onConnectionStateChanged返回一个 BluetoothGatt 对象,我必须将其保存为全局变量并用于调用其他方法,例如 discoverServices , readCharacteristic , writeCharacteristic等等,都在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 以外的东西吗?

最佳答案

听起来像 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 的贡献者,所以这有点偏颇。 🤷‍♂️

关于android - 使用 Kotlin 协程替换 BLE 回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63141333/

相关文章:

android - 如何将数据库从 SQLiteStudio 传输到 Android 手机?

android - 更改默认导航菜单的颜色

Kotlin 从委托(delegate)访问属性名称

kotlin - 使用 kotlin-dsl 检查依赖项更新

android - Alt Beacon Android 不稳定

android - 即使蓝牙已关闭,也能检测附近的信标

ios - 如何在 iOS 中将数据发送到蓝牙 LE

android - 如何在屏幕关闭时让 Android 在后台保持清醒

android - 如何在 .tflite 模型上执行迁移学习

android - Jetpack Compose 与一堆卡片的时序问题