Search code examples
androidkotlinbluetooth-lowenergyrx-androidrxandroidble

Observing connection state with RXAndroidBlE


I'm trying to listen to whether my app is connected to a bluetooth device. I'm trying to print the connectionState result but the application is not even reaching the first println so I can't check what they may be. I want to enumerate the possible connection states, and then to adjust the UI in response. How can I do this?

val rxBleClient = RxBleClient.create(this.context!!)
val bleDevice = rxBleClient.getBleDevice("34:81:F4:3C:2D:7B")

val disposable = bleDevice.establishConnection(true) // <-- autoConnect flag
 .subscribe({
  rxBleConnection ->

  // All GATT operations are done through the rxBleConnection.
  bleDevice.observeConnectionStateChanges()
  .subscribe({
   connectionState ->
   println("Connection State: $connectionState")

   if (connectionState != null) {
    enableBluetooth.setBackgroundResource(R.drawable.bluetooth_on) // Change image
    deviceConnected.setText(R.string.connected_to_hooplight) // Changed text
   } else {
    enableBluetooth.setBackgroundResource(R.drawable.bluetooth_off) // Change image
    deviceConnected.setText(R.string.connect_to_hooplight) // Changed text
   }

  }, {
   throwable ->
   Log.d("Error: ", throwable.toString())
  })
 }, {
  throwable ->
  // Handle an error here.
  Log.d("Error: ", throwable.toString())
 })

// When done... dispose and forget about connection teardown :)
disposable.dispose()

Solution

  • There are two things to the above code:

    1. disposable.dispose() should be called when the flow that was subscribed is no longer needed. If the dispose method is called right after subscription nothing will actually happen. That is why even the first println does not show up.
    2. The bleDevice.establishConnection() and bleDevice.observeConnectionStateChanges() are not dependent on each other functionally. Connection does not have to be established to observe changes. Even if one would start observing the changes after the connection is on it will only get info when the connection is closed (because it is the first change since then)

    A better way would be to decouple the observing connection changes flow and the actual connection. An example code:

    val observingConnectionStateDisposable = bleDevice.observeConnectionStateChanges()
        .subscribe(
            { connectionState ->
                Log.d("Connection State: $connectionState")
    
                if (connectionState == RxBleConnectionState.CONNECTED) { // fixed the check
                    enableBluetooth.setBackgroundResource(R.drawable.bluetooth_on) // Change image
                    deviceConnected.setText(R.string.connected_to_hooplight) // Changed text
                } else {
                    enableBluetooth.setBackgroundResource(R.drawable.bluetooth_off) // Change image
                    deviceConnected.setText(R.string.connect_to_hooplight) // Changed text
                }
            },
            { throwable -> Log.d("Error: ", throwable.toString()) }
        )
    
    val connectionDisposable = bleDevice.establishConnection(false)
        .subscribe(
            { Log.d("connection established") }, // do your thing with the connection
            { throwable -> Log.d("Error on connection: ${throwable}") }
        )