订阅可观察

时间:2017-01-19 13:13:37

标签: android rx-java

我想执行一项操作,该操作在订阅Observable后执行。目前我执行一些与BLE相关的操作,比如读取我的连接的rssi:

public class BleGattOperations {

   private class BleGattCallback extends BluetoothGattCallback {
       public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
           readRssiSubject.onNext(new RssiState(gatt, rssi, status));
       }
   }

    // Defined in Constructor
    private final BluetoothGattCallback callback;
    // Defined in Constructor
    private BluetoothGatt gatt;
    private final Subject<RssiState, RssiState> readRssiSubject = PublishSubject.create();

    public Observable<RssiState> readRssi() {
        return readRssiSubject
            .doOnSubscribe(() -> {
                 gatt.readRemoteRssi();
            })
            .take(1);
    }
}

readRssi() - 方法中,我订阅了readRssiSubject,该BleGattCallback.onReadRemoteRssi-Method()会发出gatt.readRemoteRssi()中的项目。可以通过doOnSubscribe() - 块内的readRssiSubject操作触发读取rssi操作。

不幸的是,doOnSubscribe方法在之前执行对主题的任何订阅都已完成,有时读取rssi操作的执行速度比完成onReadRemoteRssi的订阅更快。因此,在public Observable<RssiState> readRssi() { return readRssiSubject .doOnSubscribe(() -> { readRssiSubject.onNext(new RssiState()); }) .take(1); } - 方法执行后,新订阅的订阅者在订阅完成后没有收到rssi度量的结果。

也许一些实验性代码片段有助于理解基本上发生的事情:

from flask import Flask
app = Flask(__name__)



@app.route('/', methods=(['GET']))
def foo():
    return "get"


@app.route('/', methods=(['POST']))
def bar():
    return "post"

在对Subject / Observable进行订阅之后,有没有办法执行操作?

3 个答案:

答案 0 :(得分:2)

来自doOnSubscribe文档:

  

每个订阅都将导致调用给定的操作,除非源ObservableSource被引用计数,在这种情况下,源ObservableSource将为第一个订阅调用给定的操作

PublishSubject被引用计算。

替代解决方案

虽然您使用的是PublishSubject,但您似乎不会将消息从多个订阅者共享给它。在这种情况下,我会建议readRssi()的以下实现:

public Observable<RssiState> readRssi() {
    return Observable.create(emitter -> {
             // this is invoked for every new subscriber
             BluetoothGattCallback callback = 
                 (BluetoothGatt gatt, int rssi, int status) -> {
                     emitter.onNext(new RssiState(gatt, rssi, status));
                     emitter.onComplete();
                 };
             gatt.addListener(callback); // not sure about method name
             gatt.readRemoteRssi(); // initiate read
        });
}

create方法见documentation and example

答案 1 :(得分:1)

您可以使用concatEager触发多个Observable的执行并保持其排放顺序:

Observable<Data> immediate = ...
Observable<Data> async = ...

Observable.concatEager(immediate, asnyc)
.subscribe();

当立即运行时,async的值会被缓冲,直到完成,然后序列切换到异步。请注意,concatEager会从非当前来源预取有限数量的项目,也就是说,如果异步生成大量项目而立即仍处于活动状态,则会获得MissingBackpressureException

答案 2 :(得分:0)

您可以将ObservableCompletable合并,从而将操作推迟到订阅完成后:

fun <T : Any> Observable<T>.doAfterSubscribe(action: () -> Unit): Observable<T> {
    return mergeWith(Completable.fromAction(action))
}

这是其工作原理的时序图: enter image description here