RxJava2.x之结合操作符

combineLatest

当2个(最少2个)Observables中的任何一个发射了数据时,使用一个聚合函数结合每个Observable发射的最近数据项,并且基于这个函数的结果来发射数据。

先看这个操作符需要的参数,因为这个操作符可以根据一个函数来结合每个Obserbable发射的数据,但它最多传入9个Observable,这里取样为最简单的2个Observable跟一聚合个函数:

  • Observable<T1>  o1   : Observable要连接对象1
  • Observable <t2>  o2   : Observable要连接对象2
  • BiFunction<? super T1, ? super T2, ? extends R> combiner    :用来连结 o1 ,o2的一个聚合函数。

这里是简写的对象类型,只因为是要这样用而写成这样好理解些。附上源码方法:

public static <T1, T2, R> Observable<R> combineLatest(
        ObservableSource<? extends T1> source1, ObservableSource<? extends T2> source2,
        BiFunction<? super T1, ? super T2, ? extends R> combiner) {
    ObjectHelper.requireNonNull(source1, "source1 is null");
    ObjectHelper.requireNonNull(source2, "source2 is null");
    return combineLatest(Functions.toFunction(combiner), bufferSize(), source1, source2);
}

看简单的代码例子:

Observable<String> o1 = Observable.just("000", "111", "222");
        Observable<String> o2 = Observable.just("qqq", "www","eee","rrr");

        Observable.combineLatest(o1, o2, new BiFunction<String, String, String>() {
            @Override
            public String apply(String s, String s2) throws Exception {
                return s + s2 + "--";
            }
        }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                Log.d("combineLatest", "onSubscribe: ");
            }
            @Override
            public void onNext(String s) {
                Log.d("combineLatest", "onNext: " + s);
            }
            @Override
            public void onError(Throwable e) {
            }
            @Override
            public void onComplete() {
                Log.d("combineLatest", "onComplete: ");
            }
        });

 看输出结果:

04-23 16:29:56.783 3144-3144/com.example.testlink D/combineLatest: onSubscribe: 
04-23 16:29:56.793 3144-3144/com.example.testlink D/combineLatest: onNext: 222qqq--
04-23 16:29:56.793 3144-3144/com.example.testlink D/combineLatest: onNext: 222www--
04-23 16:29:56.793 3144-3144/com.example.testlink D/combineLatest: onNext: 222eee--
04-23 16:29:56.793 3144-3144/com.example.testlink D/combineLatest: onNext: 222rrr--
04-23 16:29:56.793 3144-3144/com.example.testlink D/combineLatest: onComplete: 

一开始没有看到输出结果,只看操作符介绍时猜测会产生12种输出结果,2个Observable各自发送了3,4个数据,按照组合排列应该是产生12种结果。但事实却打脸了,只有四种。至此,不得不在理解分析一下。看它的示意图:

 看这个图跟最上面的介绍了应该是这样的,每个Observable发送一次数据都会拿到当前发射的这个数据跟另一个Observable最近发射的数据,通过这个聚合函数再来处理。因此上面的应该是o1先发射了所有数据源,然后再发射o2的数据源。当然对于o1最近的一个就是最后一个了。所以每次o2发射,聚合函数处理的2个数据源是o1的最后一个跟o2的所有数据了。对此我再修改一下o1,看运行结果是否这样,o1修改成这样: 

Observable<Long> o1 = Observable.interval(1000, TimeUnit.MILLISECONDS).take(3);

对应的聚合函数修改:

Observable.combineLatest(o1, o2, new BiFunction<Long, String, String>() {
    @Override
    public String apply(Long s, String s2) throws Exception {
        return s + s2 + "--";
    }

 运行结果:

D/combineLatest: onSubscribe: 
D/combineLatest: onNext: 0rrr--
D/combineLatest: onNext: 1rrr--
D/combineLatest: onNext: 2rrr--
D/combineLatest: onComplete:  

o1每延迟一秒发射一个数据,共发射3个数据,而o2没有处理,最终o1会先o1发生完数据,等o1发生数据跟o2最近发射的数据是o2的最后一个数据。 聚合函数处理的2个数据源是o1的所有数据跟o2的最后一个数据。

但其实还有一个疑问,每次的结果都是o1或o2的最后一个数据跟另一个Observable的所有数据处理。那究竟是否可以认为combineLatest 总是2者之一的最后一个数据才会参与函数处理呢?还是因为发射效率过快导致的?为了证实一下这个问题这里再改变一下条件来看结果。首先将延迟时间缩短到可以忽略,最后确定时间为1毫秒,另一个发射的数据要足够多,为10个。最终结果:

D/combineLatest: onSubscribe: 
D/combineLatest: onNext: 0qqq--
D/combineLatest: onNext: 0www--
D/combineLatest: onNext: 0eee--
D/combineLatest: onNext: 0rrr--
D/combineLatest: onNext: 1rrr--
D/combineLatest: onNext: 2rrr--
D/combineLatest: onNext: 2ttt--
D/combineLatest: onNext: 2yyy--
D/combineLatest: onNext: 2uuu--
D/combineLatest: onNext: 2iii--
D/combineLatest: onNext: 2ooo--
D/combineLatest: onNext: 2ppp--
D/combineLatest: onComplete: 

结论:o1,o2是同步进行发射的,只是效率极快。而不是总是2者之一的最后一个数据才会参与函数处理。

join

引用来自翻译文档的解释:

任何时候,只要在另一个Observable发射的数据定义的时间窗口内,这个Observable发射了一条数据,就结合两个Observable发射的数据。

Join操作符结合两个Observable发射的数据,基于时间窗口(你定义的针对每条数据特定的原则)选择待集合的数据项。你将这些时间窗口实现为一些Observables,它们的生命周期从任何一条Observable发射的每一条数据开始。当这个定义时间窗口的Observable发射了一条数据或者完成时,与这条数据关联的窗口也会关闭。只要这条数据的窗口是打开的,它将继续结合其它Observable发射的任何数据项。你定义一个用于结合数据的函数。

感觉看完也不是很理解。不急,看看方法参数,再写个例子,再回头理解理解。先看方法,方法需要传入4个参数:

  • ObservableSource<? extends TRight> other  : 参与结合函数的另一个Observable
  • Function<? super T, ? extends ObservableSource<TLeftEnd>> leftEnd: 接收初始Observable的数据,返回时间窗口的Observables
  • Function<? super TRight, ? extends ObservableSource<TRightEnd>> rightEnd: 接收other Observable的数据,返回时间窗口的Observables
  • BiFunction<? super T, ? super TRight, ? extends R> resultSelector :结合函数

简单实现:

Observable<String> o1 = Observable.just("111", "222", "333");
        Observable.just("aaa", "bbb", "ccc")
                .join(o1, new Function<String, Observable<Long>>() {
                    @Override
                    public Observable<Long> apply(String s) throws Exception {
                        Log.d("join", "apply1: " + s);
                        return Observable.timer(10, TimeUnit.MILLISECONDS);
                    }
                }, new Function<String, Observable<Long>>() {
                    @Override
                    public Observable<Long> apply(String s) throws Exception {
                        Log.d("join", "apply2: " + s);
                        return Observable.timer(10, TimeUnit.MILLISECONDS);
                    }
                }, new BiFunction<String, String, String>() {
                    @Override
                    public String apply(String s, String s2) throws Exception {
                        return s + "_" + s2;
                    }
                }).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
            }

            @Override
            public void onNext(String s) {
                Log.d("join", "onNext: " + s);
            }
            @Override
            public void onError(Throwable e) {
            }
            @Override
            public void onComplete() {
            }
        });

输出结果:

 D/join: apply1: aaa
 D/join: apply1: bbb
 D/join: apply1: ccc
 D/join: apply2: 111
 D/join: onNext: aaa_111
 D/join: onNext: bbb_111
 D/join: onNext: ccc_111
 D/join: apply2: 222
 D/join: onNext: aaa_222
 D/join: onNext: bbb_222
 D/join: onNext: ccc_222
 D/join: apply2: 333
 D/join: onNext: aaa_333
 D/join: onNext: bbb_333
 D/join: onNext: ccc_333

 4个参数中只能第二个跟第三个稍微晦涩些,但是这2个又是相同逻辑的。解释里面说了,这2个Function是基于时间窗口,选择待集合的数据项。数据来源无非就2个Observable里发射的数据。然后时间窗口实现为Observables,这里就可以代入理解为一个定时器,在定时的这段时间内收集的数据,会参与第4个函数处理。从输出结果上理解:代码的时间窗口实现为一个timer,两个Observable的定时都是10毫秒。在10毫秒内,2个Observable都发射完了自己的数据,最终在结合函数处理下输出了2个Observable数据的所有的组合情况。2个Observable是同时进行的,基于各自的时间窗口收集的数据而产生不同的结果。

Concat

concat没有join跟combinelast那么复杂的操作。没有结合函数,没有时间窗口。它很简单,只需要传入Observable,然后订阅即可。Observable上限为4个,而且会按照参数顺序发射每个Observable里的数据。

Observable<String> o1 = Observable.just("111", "222", "333");
        Observable<String> o2 = Observable.just("aaa", "bbb", "ccc");
        Observable<Long> o3 = Observable.interval(1000, TimeUnit.MILLISECONDS).take(3);
        Observable<String> o4 = Observable.just("x", "xx", "xxx");
        Observable.concat(o1, o2,o3,o4).subscribe(new Consumer<Serializable>() {
            @Override
            public void accept(Serializable serializable) throws Exception {
                Log.d("concat", "accept: "+serializable.toString());
            }
        });

按照顺序输出,即使中间有个延时Observable 

D/concat: accept: 111
D/concat: accept: 222
D/concat: accept: 333
D/concat: accept: aaa
D/concat: accept: bbb
D/concat: accept: ccc
D/concat: accept: 0
D/concat: accept: 1
D/concat: accept: 2
D/concat: accept: x
D/concat: accept: xx
D/concat: accept: xxx

Merge

合并多个Observables的发射数据,好像它们是一个单个的Observable一样。和concat极其相似,但是merge可能会让合并的Observables发射的数据错乱,但是concat不会让数据交错,它会按顺序一个接着一个发射多个Observables的发射物。例子可以参考concat,这里不做演示。

Zip

将多个Observables(最多9个)的发射数据结合到一起,基于这个函数的结果为每个结合体发射单个数据项。它按照严格的顺序应用这个函数,一一对应。它只发射与发射数据项最少的那个Observable一样多的数据。

方法参数介绍:

  • ObservableSource<? extends T1> source1  : 用于结合数据的Observable,可以有多个,最多9个;
  • BiFunction<? super T1, ? super T2, ? extends R> zipper :结合函数

举个栗子:

Observable<String> o1 = Observable.just("111", "222", "333");
//        Observable<String> o2 = Observable.just("aaa");
        Observable<Long> o3 = Observable.interval(1000, TimeUnit.MILLISECONDS).take(2);
        Observable.zip(o1, o3, new BiFunction<String, Long, Integer>() {
            @Override
            public Integer apply(String s, Long s2) throws Exception {
                Log.d("zip", "apply: s= " + s + " s2= " + s2);
                return (s + s2).length();
            }
        }).subscribe(new Consumer<Integer>() {
            @Override
            public void accept(Integer integer) throws Exception {
                Log.d("zip", "accept: " + integer);
            }
        });
    }

输出结果:

D/zip: apply: s= 111 s2= 0
D/zip: accept: 4
D/zip: apply: s= 222 s2= 1
D/zip: accept: 4

StartWith 

在数据序列的开头插入一条指定的项,可以是一个Observable,也可以是一个发射数据。例子很简单:

Observable.just("111")
        .startWith("qqqq")
        .subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d("startWith", "accept: " + s);
            }
        });
/** 输出结果:
 * D/startWith: accept: qqqq
 * D/startWith: accept: 111
 */

switchOnNext

引用翻译文档的解释:

switchOnNext订阅一个发射多个Observables的Observable。它每次观察那些Observables中的一个,switchOnNext返回的这个Observable取消订阅前一个发射数据的Observable,开始发射最近的Observable发射的数据。注意:当原始Observable发射了一个新的Observable时(不是这个新的Observable发射了一条数据时),它将取消订阅之前的那个Observable。这意味着,在后来那个Observable产生之后到它开始发射数据之前的这段时间里,前一个Observable发射的数据将被丢弃(就像图例上的那个黄色圆圈一样)。

 通俗点就是说: switchOnNext用来发射多个Observable的数据,如果Observable之间发射时机重叠了就忽略前一个Observable的未发射的数据,发射后一个Observable的数据,按照顺序直到最后。代码实例无(以后考虑补上)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值