October 11, 2017   |   3min read

Maintaining Open-Source RxAndroidBle Library (Storytelling)


This is the second part of the series devoted to maintaining our RxAndroidBle library. If you want to know how it all began, check it here. In the following article, I will analyze three attempts of designing the right abstraction to interact with. The aim was to wrap the cumbersome Android BLE API into handy RxJava Observables in a way that will be easy to understand and use.

Attempt #1

During few months of working with the native API, we have gathered enough domain knowledge to know what to look for and where to get the full picture of what is going on. We wanted to route the information to the place where the user would expect it to surface. Sounds good, right?

But it can be improved.

Most of the “Rx” libraries are just plain simple wrappers over the API that was provided—and that was our first approach. We have wrapped the native Android abstraction:

BluetoothAdapter became RxBleClient
BluetoothDevice became RxBleDevice
BluetoothGatt became RxBleGatt

Even though it was easier to use because of routing the potential errors, this abstraction was still very stateful. The users would need to manually call .connect() and .disconnect() on the RxBleGatt. Before interacting with characteristics, they would need to check whether a call to .readCharacteristic() could succeed by checking if the RxBleGatt was still connected.

Managing state is one of the hardest parts of developing programs and wrong management is the most common source of bugs. We could do better. We had the client, the device and the GATT which we needed to connect and disconnect to manage its state… so maybe we were just dealing with a connection?

Attempt #2

BluetoothAdapter became RxBleClient
BluetoothDevice became RxBleDevice
BluetoothGatt became RxBleConnection

This intuitively felt better. We were dealing with the client which is the main entry point, the device and the connection of this device. Unfortunately, it was not perfect yet. The user would still need to call .connect() and .disconnect() on the RxBleDevice and check the state of the RxBleConnection prior to using it. But hey! Maybe the user is not really interested in managing the connection but rather in establishing it and using afterwards?

Attempt #3

BluetoothAdapter became RxBleClient
BluetoothDevice became RxBleDevice
BluetoothGatt became RxBleConnection*

* The RxBleConnection has become available as a result of calling .establishConnection() on the RxBleDevice.

So now the users would get a valid connection as long as they are interested in it by staying subscribed to the .establishConnection(). Once the user unsubscribes, the connection will be torn down and everyone will be happy. The connection is managed automatically, depending on user intentions. There is a single place for starting and closing the connection, one place to receive an error and there is no need to keep the RxBleConnection since the new one will be created once the user becomes interested in it again. This abstraction proved to leave much smaller space for state managing errors.

Stay tuned!

Sometimes you need to think beyond the already established way in order to achieve better results. Stay tuned for the next part of the series. We will discuss the API design!

Darek Seweryn

Staff Software Engineer

Did you enjoy the read?

If you have any questions, don’t hesitate to ask!