如何以线性方式连接两个可观察的操作(首先做这个事情,然后做一个事情做第二件事)? [英] How to concatenate two observable operations in a linear fashion (do first this thing and after that one finishes do the second thing)?

查看:77
本文介绍了如何以线性方式连接两个可观察的操作(首先做这个事情,然后做一个事情做第二件事)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Polidea发布了一个新的方便的库,称为RxAndroidBle ,对于处理许多问题非常有用当您使用香草蓝牙API时.

Polidea has released a new handy library called RxAndroidBle which is very useful for dealing with a lot of issues when you're using vanilla Bluetooth APIs.

在进一步解释之前,我们的想法是拥有一个POJO模型,该模型具有设备发送给我的所有最新值(在这种情况下由Map对象表示):

Before explaining more the idea is to have a POJO model that has all the recent values that the device send (or I query) to me (in this case is represented by a Map object):

如果我想收到有关多个特征通知的通知,可以执行以下操作:

If I want to be notified about multiple characteristic notifications I can do this:

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 */}
        );

现在,当我连接到设备时,通知将更新POJO对象(在此示例中为Map).

And now when I'm connected to the device the notifications are updating the POJO object (the Map in this particular example).

如果我想读取值,可以执行以下操作:

If I want to read values I can do the following:

 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 */}
    );

我的主要问题是:

我想在第一次连接时:读取具有读取属性的大量特征,并且仅在此之后订阅具有通知属性的那些通知.这是连接操作.我该如何实现?

I would like to upon the first connection: read an amount of characteristics that has the reading property and only after that subscribe to those notifications that have the notification property. This is concatenate the operations. How I can achieve this?

问题是当我阅读本书的第一部分时,可观察的对象读取了这些特性属性,但不会像等待更多的那样发出doOnComplete方法,因此我无法启动或编写下一个正在订阅和执行的下一个操作聆听变化.

The thing is when I do the first part of the reading, the observable read those characteristics properties but won't emit a doOnComplete method as is waiting for more so I can't kickstart or compose the next operation which is subscribing and listening to changes.

我肯定知道具有read属性的特征量,但是我想以一种通用的方式进行操作(即,我具有要读取的7个或15个特征都没有关系,我只想全部读取它们,编写pojo值,然后开始监听通知.

I know for sure the amount of characteristic that has the read property but I would like to do it in a generic fashion (i.e it doesn't matter if I have 7 or 15 characteristics that I want read, I only want to read them all, write the pojo values, and after that start listening the notifications).

也许选择是组成一个可观察对象,该对象对成功的阅读进行计数,然后开始监听通知.

Maybe the option is to compose an observable that counts the successful reading and after that it starts listening notifications.

实现这一目标的最佳反应方式是什么?

How is the best reactive approach to achieve that?

让您处于这种情况是t 产生该问题的原始线程.

To put you in situation this is the original thread that spawned this question.

推荐答案

要实现所需的目标,可以采取几种方法.其中之一是:

To achieve what you want you can take several ways. One of them is:

    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 */}
            );

位置:

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
}

或者,除了 concatWith()之外,您还可以颠倒顺序并使用 startWith().

Alternatively to concatWith() you could inverse the order and use startWith().

最好的问候

这篇关于如何以线性方式连接两个可观察的操作(首先做这个事情,然后做一个事情做第二件事)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆