简体   繁体   English

RxJava Observable在首次发射时得到通知

[英]RxJava Observable get notified on first emission

I have three Observables which I combine with combineLastest: 我将三个Observable与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;
        }
    });

I want to be notified about the first emission of one of the Observables without ignoring the later emissions, which I guess first operator would do. 我想被通知有关一个可观察物的第一次排放,而又不忽略后来的排放,我想第一位操作员会这样做。 Is there a convenient operator for that like (example): 是否有类似这样的便捷运算符(示例):

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

I think you can have a practical doOnFirst with a simple take if you're handling a stream: 我认为,如果您要处理流,则可以通过简单的操作take实现实用的doOnFirst

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

This way the action is only bound to the first item. 这样,动作仅绑定到第一项。

This could be changed to handle observables which are not backed by streams adding skip to skip the already taken items: 可以将其更改为处理没有流支持的可观察对象,添加skip以跳过已采取的项目:

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

There are a couple of solutions I can think of. 我可以想到几种解决方案。 The first one is an ugly but simple hack of doOnNext. 第一个是doOnNext的丑陋但简单的技巧。 Just add a boolean field to the Action1 indicating whether the first item has been received. 只需向Action1添加一个布尔字段,指示是否已接收到第一项。 Once received, do whatever it is you want to do, and flip the boolean. 收到后,执行您想做的任何事情,然后翻转布尔值。 For example: 例如:

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

        boolean first = true;

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

The second one is to subscribe twice on the observable you want to monitor using publish or share() , with one of those publications going through first (depending on whether you want to manually connect to the published observable). 第二个是使用publishshare()对要监视的可观察对象进行两次订阅,其中一个发布会first (取决于您是否要手动连接到已发布的可观察对象)。 You'll end up with two separate observables that emit the same items, only the first one will stop after the first emission: 您最终将得到两个单独的可观察项,它们发出相同的项,只有第一个可观察项将在第一次发出后停止:

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

Using rxjava-extras : 使用rxjava-extras

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

It's unit tested and under the covers just uses a per-subscription counter in an operator. 它已经过单元测试,在幕后仅在运营商中使用每个订阅计数器。 Note that per-subscription is important as there are plenty of uses cases where an observable instance gets used more than once and we want the doOnFirst operator to apply each time. 请注意,按预订非常重要,因为在许多用例中,可观察实例被多次使用,并且我们希望doOnFirst运算符每次都适用。

Source code is here . 源代码在这里

For convenience, I created these extension functions for Flowable and Observable . 为了方便起见,我为FlowableObservable创建了这些扩展功能。
Note, that with doOnFirst() the action will be called before the first element emission, whilst doAfterFirst() will firstly emit the first item and then perform the action. 注意,使用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))

Usage is as simple as this: 用法很简单:

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

Output: 输出:

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

And: 和:

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

Output: 输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM