louiscad
12/06/2017, 11:22 AMBluetoothGattCallback
instance with the overriden methods you'll need once, when connecting, and the connection result, the attributes discovery and read/write operations are passed to this callback. What I aim at is to use coroutines to handle failures without callback hell, in a procedural style, and to handle success this way too. The issue that I have is that this BluetoothGattCallback
listens to too many different things. When connecting, I'm just interested in the connectionState callback. When writing data, I'm just interested in waiting for completion or error and knowing if it succeeded or failed, when reading data, just need the data, or exception... Is it possible to separate these things from this god callback?
For reference, here is the key method with the two BluetoothGatt
and BluetoothGattCallback
key classes in its signature:
<https://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#connectGatt(android.content.Context>, boolean, android.bluetooth.BluetoothGattCallback)
(select the whole link to get directed to the right method, slack doesn't like this url formatting)
Please, reply in thread since this is quite specific to Android, so this channel doesn't get too clutteredelizarov
12/06/2017, 12:00 PMdata class ConnectionState(val status: Int, state: Int)
val NOT_CONNECTED = ConnectionState(0, 0) // or whatever
val stateChannel = ConflatedChannel<ConnectionState>(NOT_CONNECTED)
Then, in the callaback’s onConnectionStateChange
I would do stateChannel.offer(ConnectionState(status, newState))
suspend fun connect() {
performConnection()
for (connectionState in stateChannel) {
if (connectionState.isGood) break
}
}
louiscad
12/06/2017, 4:42 PMsuspend fun BluetoothDevice.getBroadcastingIntervalMillis(): Int {
val gatt = connect(bleDevice) // Suspends until connection succeeds, fails or times out
val uuid = EddystoneServiceSpec.broadcastingIntervalUuid
val broadcastingIntervalCharacteristic = gatt.readCharacteristic(uuid) // Suspends until characteristic is read, or throws on failure or disconnection
gatt.close()
return broadcastingIntervalCharacteristic.getIntValue(FORMAT_UINT32, 0)!!
}
Version that leaves the connection open, and throws on failures or disconnections:
suspend fun BluetoothGatt.getBroadcastingIntervalMillis(): Int {
check(isConnected())
val uuid = EddystoneServiceSpec.broadcastingIntervalUuid
val broadcastingIntervalCharacteristic = gatt.readCharacteristic(uuid) // Suspends until characteristic is read, or throws
return broadcastingIntervalCharacteristic.getIntValue(FORMAT_UINT32, 0)!!
}
elizarov
12/06/2017, 7:03 PMconnectGatt
? You should have this invocation somewhere. What I would do is to crate a class GattConnection
that is produced as the result of that connectGatt
invocation. This class keeps a callback and all the channels inside as private vals. Now, you can define all the methods you need in your bluetooth API as members of GattConnection
class. They will have access to those private channels and work via them.louiscad
12/07/2017, 8:25 AMconnect(...)
hypothetical method seen in the second line of my first code snippet would have called connectGatt(...)
under the hood.
Thanks for your hint, I will try to make it work