2016-08-25 1 views
4

Polidea a publié un nouveau handy library called RxAndroidBle qui est très utile pour faire face à beaucoup de problèmes lorsque vous utilisez des API Bluetooth vanille.Comment concaténer deux opérations observables de façon linéaire (faire d'abord cette chose et après que l'on termine la deuxième chose)?

Avant d'expliquer plus l'idée est d'avoir un modèle POJO qui a toutes les valeurs récentes que l'envoi de l'appareil (ou je requête) pour moi (dans ce cas est représenté par un objet Carte):

Si je souhaitez être averti de notifications multiples caractéristiques que je peux faire:

final UUID serviceUuid = // your service UUID 
final Map<UUID, byte[]> genericModel = new HashMap<>(); 
final Observable<RxBleConnection> connectionObservable = // your connectionObservable 

connectionObservable 
     .flatMap(connection -> 
       connection.discoverServices() 
         .flatMap(services -> services.getService(serviceUuid).map(BluetoothGattService::getCharacteristics)) // get characteristics you're interested in 
         .flatMap(Observable::from) // deal with every characteristic separately 
         .flatMap(characteristic -> connection 
             .setupNotification(characteristic) // setup notification for each 
             .flatMap(observable -> observable), // to get the raw bytes from notification 
           Pair::new) // merge characteristic with byte[] to keep track from which characteristic the bytes came 
     ) 
     .subscribe(
       pair -> genericModel.put(pair.first.getUuid(), pair.second), 
       throwable -> { /* handle errors */} 
     ); 

Et maintenant, quand je suis connecté à l'appareil les notifications sont mise à jour l'objet POJO (la carte dans cet exemple).

Si je veux lire des valeurs que je peux faire ce qui suit:

connectionObservable.flatMap(connection -> 
    connection.discoverServices() 
     .flatMap(services -> services.getService(SERVICE_ID).map(BluetoothGattService::getCharacteristics)) 
     .flatMap(Observable::from) 
     .filter(characteristic -> BleUtils.hasReadProperty(characteristic.getProperties())) 
     .flatMap(connection::readCharacteristic, Pair::new) 
) 
    .subscribe(
      pair -> genericModel.put(pair.first.getUuid(), pair.second), 
      throwable -> { /* handle errors */} 
    ); 

Ma question principale est:

Je voudrais sur la première connexion: lire une quantité de caractéristiques qui a la lecture propriété et seulement après que souscrivent à ces notifications qui ont la propriété de notification. Ceci est concaténer les opérations. Comment je peux y arriver? La chose est quand je fais la première partie de la lecture, l'observable lit ces propriétés de caractéristiques mais n'émettra pas une méthode de doOnComplete en attendant plus que je ne peux pas kickstart ou composer l'opération suivante qui est souscrite et écouter les changements.

Je sais avec certitude la quantité de caractéristique qui a la propriété de lecture, mais je voudrais le faire de manière générique (c'est-à-dire si j'ai 7 ou 15 caractéristiques que je veux lire, je veux seulement pour les lire tous, écrivez les valeurs de pojo, et après cela commencez à écouter les notifications).

Peut-être que l'option est de composer un observable qui compte la lecture réussie et après cela il commence à écouter les notifications.

Quelle est la meilleure approche réactive pour y parvenir? Pour vous mettre en situation c'est he original thread that spawned this question.

+0

Il y a la 'concat',' 'concatWith' et opérateurs concatEager' pour concaténations commandés. – akarnokd

Répondre

1

Pour réaliser ce que vous voulez, vous pouvez prendre plusieurs façons. L'un d'eux est:

final UUID serviceUuid = // your service UUID 
    final Map<UUID, byte[]> genericModel = new HashMap<>(); 
    final Observable<RxBleConnection> connectionObservable = // your connectionObservable 

    connectionObservable 
      .flatMap(// get the characteristics from the service you're interested in 
        connection -> connection 
          .discoverServices() 
          .flatMap(services -> services 
            .getService(serviceUuid) 
            .map(BluetoothGattService::getCharacteristics) 
          ), 
        Pair::new 
      ) 
      .flatMap(connectionAndCharacteristics -> { 
       final RxBleConnection connection = connectionAndCharacteristics.first; 
       final List<BluetoothGattCharacteristic> characteristics = connectionAndCharacteristics.second; 
       return readInitialValues(connection, characteristics) 
         .concatWith(setupNotifications(connection, characteristics)); 
      }) 
      .subscribe(
        pair -> genericModel.put(pair.first.getUuid(), pair.second), 
        throwable -> { /* handle errors */} 
      ); 

Où:

private Observable<Pair<BluetoothGattCharacteristic, byte[]>> readInitialValues(RxBleConnection connection, 
                       List<BluetoothGattCharacteristic> characteristics) { 
    return Observable.from(characteristics) // deal with every characteristic separately 
      .filter(characteristic -> (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_READ) != 0) // filter characteristics that have read property 
      .flatMap(connection::readCharacteristic, // read characteristic 
        Pair::new); // merge characteristic with byte[] to keep track from which characteristic the bytes came 
} 

private Observable<Pair<BluetoothGattCharacteristic, byte[]>> setupNotifications(RxBleConnection connection, 
                       List<BluetoothGattCharacteristic> characteristics) { 
    return Observable.from(characteristics) // deal with every characteristic separately 
      .filter(characteristic -> (characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) // filter characteristics that have notify property 
      .flatMap(characteristic -> connection 
          .setupNotification(characteristic) // setup notification for each 
          .flatMap(observable -> observable), // to get the raw bytes from notification 
        Pair::new); // merge characteristic with byte[] to keep track from which characteristic the bytes came 
} 

Alternativement à concatWith() vous pourriez inverser l'ordre et utiliser startWith().

Cordialement

+0

Merci! Une chose dont je n'ai pas tenu compte était la composition des observables. Mettre correctement le code en retrait est préférable pour comprendre chaque opération. Merci beaucoup! :) –