簡體   English   中英

使用 Kotlin 協程替換 BLE 回調

[英]Replace BLE callbacks using Kotlin Coroutines

我想使用 Kotlin 的協程來處理 BLE 的異步回調。 連接到 BLE 設備需要回調 object,類似於:

connectToBle(Context, Boolean, GattCallback)

結果在 GattCallback object 的onConnectionStateChanged方法中異步返回。我使用suspendCoroutine<BluetoothGatt>來實現它,詳見此處的文檔。

現在onConnectionStateChanged返回一個 BluetoothGatt object ,我必須將其保存為全局變量並用於調用其他方法,例如discoverServicesreadCharacteristicwriteCharacteristic等,所有這些方法都在 GattCallback object 的不同回調方法中異步返回,例如onServicesDiscoveredonCharacteristicReadonCharacteristicWrite等等。

這是使用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的貢獻者,所以這是一個有偏見的自我插件。 ♂️

如果有人仍在尋找答案,則可以使用協程通道(或者也可以使用 callbackFlow)來實現

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM