Skip to content

Connection Management

Kevin Babcock edited this page Feb 22, 2019 · 14 revisions

RxCentralBle provides a CoreConnectionManager implementation of the ConnectionManager interface. The CoreConnectionManager respects Bluetooth state and handles all scanning and connection logic via the connect() method.

Upon a successful connection, the connect() method emits a new GattIO reference, which is the reactive bridge to the imperative BluetoothGatt and BluetoothGattCallback APIs. Pass the latest GattIO into your GattManager to activate the GattManager.

BluetoothDetector bluetoothDetector = new CoreBluetoothDetector(context);

GattManager gattManager = new CoreGattManager();

ConnectionManager connectionManager = new CoreConnectionManager(context, 
  bluetoothDetector, 
  new CoreGattIO.Factory());

ScanMatcher scanMatcher = new CustomScanMatcher();

// Connect to a peripheral.
Disposable connection = connectionManager
  .connect(scanMatcher, DEFAULT_SCAN_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT)
  .subscribe(
        gattIO -> {
          // Inject the latest connected GattIO into your GattManager..
          gattManager.setGattIO(gattIO);
        },
        error -> {
          // Connection lost.
        };

Dispose of your connection subscription to disconnect:

connection.dispose();

Error Handling

Connections can be retried. If a recoverable connection error occurs, it will be thrown as a ConnectionError on the connect() stream. The below logic will retry the connection after each ConnectionError. The entire scanning, matching, and connection process will be repeated on each retried subscription to connect().

// Connect to a peripheral.  Retry each time a there is a ConnectionError, such as a disconnection.
connectionManager
  .connect(scanMatcher, DEFAULT_SCAN_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT)
  .retryWhen(
         errors ->
             errors
                 .flatMap(
                   error -> {
                     if (error instanceof ConnectionError) {
                       return Observable.just(Irrelevant.INSTANCE);
                     }
  
                     return Observable.error(error);
                   }
               )
  .subscribe(
        gattIO -> {
          // Inject the latest connected GattIO into your GattManager..
          gattManager.setGattIO(gattIO);
        },
        error -> {
          // Unexpected error.
        };

Peripheral "Prep"

You can also perform a set of operations before injecting the GattIO into the GattManager. For example, perhaps there is a requirement to register for notifications prior to running other operations on a peripheral:

// Connect to a peripheral where notifications must be registered prior to running other operations.
connectionManager
  .connect(scanMatcher, DEFAULT_SCAN_TIMEOUT, DEFAULT_CONNECTION_TIMEOUT)
  .switchMapSingle(
          gattIO ->
                  new RegisterNotification(
                          SVC_UUID,
                          READ_CHR_UUID,
                          5000)
                  .executeWithResult(gattIO)
                  .flatMap(irrelevant -> Single.just(gattIO)))
  .switchMapSingle(
          gattIO ->
                  new RegisterNotification(
                          SVC_UUID,
                          DATA_CHR_UUID,
                          5000)
                  .executeWithResult(gattIO)
                  .flatMap(irrelevant -> Single.just(gattIO)))
  .subscribe(
        gattIO -> {
          // Give your GattManager the latest connected GattIO.
          gattManager.setGattIO(gattIO);
        },
        error -> {
          // Connection lost.
        };