RxJava Observable在第一次发射时得到通知

时间:2015-11-22 20:54:43

标签: reactive-programming rx-java

我有三个Observables,我与combineLastest结合使用:

    Observable<String> o1 = Observable.just("1");
    Observable<String> o2 = Observable.just("2");
    Observable<String> o3 = Observable.just("3");

    Observable.combineLatest(o1, o2, o3, new Func3<String, String, String, Object>() {
        @Override
        public Object call(String s, String s2, String s3) {
            return null;
        }
    });

我希望收到关于其中一个Observable的首次发射的通知,而不会忽略后来的排放,我猜first operator会这样做。是否有一个方便的操作员(例如):

    o1.doOnFirst(new Func1<String, Void>() {
        @Override
        public Void call(String s) {
            return null;
        }
    })

4 个答案:

答案 0 :(得分:9)

如果您正在处理流,我认为您可以使用简单的take实用doOnFirst

public static <T> Observable<T> withDoOnFirst(Observable<T> source, Action1<T> action) {
    return source.take(1).doOnNext(action).concatWith(source);
}

这样,动作仅绑定到第一个项目。

这可以更改为处理由流添加skip以跳过已经采取的项目的 支持的观察项:

public static <T> Observable<T> withDoOnFirstNonStream(Observable<T> source, Action1<T> action) {
    return source.take(1).doOnNext(action).concatWith(source.skip(1));
}

答案 1 :(得分:4)

我能想到几个解决方案。 第一个是doOnNext的丑陋而简单的黑客攻击。只需在Action1中添加一个布尔字段,指示是否已收到第一个项目。收到后,做你想做的任何事情,然后翻转布尔值。例如:

Observable.just("1").doOnNext(new Action1<String>() {

        boolean first = true;

        @Override
        public void call(String t) {
            if (first) {
                // Do soemthing
                first = false;
            }
        }
    });

第二个是使用publishshare()在您要监控的可观察量上订阅两次,其中一个出版物通过first(取决于您是否要手动连接到已发布的observable)。你最终会得到两个发出相同项目的独立观察者,只有第一个观察者会在第一次发射后停止:

ConnectableObservable<String> o1 = Observable.just("1").publish();

o1.first().subscribe(System.out::println); //Subscirbed only to the first item
o1.subscribe(System.out::println); //Subscirbed to all items

o1.connect(); //Connect both subscribers

答案 2 :(得分:2)

使用rxjava-extras

observable
  .compose(Transformers.doOnFirst(System.out::println))

它经过了单元测试,并且在操作员中使用了每个订阅计数器。请注意,每个订阅很重要,因为有很多用例,可观察的实例被多次使用,我们希望每次都应用doOnFirst运算符。

源代码为here

答案 3 :(得分:1)

为方便起见,我为FlowableObservable创建了这些扩展功能。
请注意,使用doOnFirst()会在发出第一个元素之前调用该动作,而doAfterFirst()首先会发出第一个项目,然后执行该动作。

fun <T> Observable<T>.doOnFirst(onFirstAction: (T) -> Unit): Observable<T> =
    take(1)
        .doOnNext { onFirstAction.invoke(it) }
        .concatWith(skip(1))

fun <T> Flowable<T>.doOnFirst(onFirstAction: (T) -> Unit): Flowable<T> =
    take(1)
        .doOnNext { onFirstAction.invoke(it) }
        .concatWith(skip(1))

fun <T> Observable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Observable<T> =
    take(1)
        .doAfterNext { afterFirstAction.invoke(it) }
        .concatWith(skip(1))

fun <T> Flowable<T>.doAfterFirst(afterFirstAction: (T) -> Unit): Flowable<T> =
    take(1)
        .doAfterNext { afterFirstAction.invoke(it) }
        .concatWith(skip(1))

用法很简单:

Flowable.fromArray(1, 2, 3)
            .doOnFirst { System.err.println("First $it") }
            .subscribe { println(it) }

输出:

// First 1  
// 1  
// 2  
// 3

并且:

Flowable.fromArray(1, 2, 3)
            .doAfterFirst { System.err.println("First $it") }
            .subscribe { println(it) }

输出:

// 1  
// First 1
// 2  
// 3