Android从零开始学习Rxjava2(七)—— 组合运算符

rxjava2组合运算符

使用多个源Observable创建单个Observable的运算符

Merge

通过合并它们的排放,将多个Observable组合成一个。合并可以交错合并的Observables发出的项目。并且任何源Observable的onError通知将立即传递给观察者并终止合并的Observable。
在这里插入图片描述
merge合并,就像多个进水管往水池注水,最终合成一个Observable。简单来说就是多输入,单输出。
举个例子,将两个Observable的数据在一起打印:

private void doSomeWork() {
        Observable.merge(Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
                observableEmitter.onNext("0");
                Thread.sleep(100);
                observableEmitter.onNext("2");
                Thread.sleep(100);
                observableEmitter.onNext("4");
                Thread.sleep(100);
                observableEmitter.onNext("6");
                Thread.sleep(100);
                observableEmitter.onComplete();
            }
        }).subscribeOn(Schedulers.io()), Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
                observableEmitter.onNext("1");
                Thread.sleep(50);
                observableEmitter.onNext("3");
                Thread.sleep(50);
                observableEmitter.onNext("5");
                Thread.sleep(50);
                observableEmitter.onNext("7");
                Thread.sleep(50);
                observableEmitter.onComplete();

            }
        }).subscribeOn(Schedulers.io())).subscribe(new Consumer<String>() {
            @Override
            public void accept(String s) throws Exception {
                Log.d(TAG, " accept : s : " + s);
            }
        });
    }

打印结果

accept : s : 0
accept : s : 1
accept : s : 3
accept : s : 2
accept : s : 5
accept : s : 7
accept : s : 4
accept : s : 6

上面打印结果可以发现,发射的数据被交叉合并到一个Observable里面。但是如果去掉subscribeOn(Schedulers.io())),同步的合并Observable,它们将连接在一起并且不会交叉。其实如果想不交错的合并,也可以使用运算和聚合运算符中的Concat运算符。在这里插入图片描述
我们有可能遇到这种问题,需要merge的多个Observable中,有一个发射了Error,比如多个请求接口数据共同展示一个页面,但是其中一个接口先请求得到结果而且是Error,这时候merge会失败异常。我们其实需要将异常放在这几个接口之后处理,则merge不能很好的满足需求。不要担心,rx提供了另外一个mergeDelayError操作符,可以实现。

MergeDelayError

通过合并它们的排放,将多个Observable组合成一个。合并可以交错合并的Observables发出的项目。遇到onError通知先保留onError通知,直到所有合并的Observable完成,然后才将它传递给观察者:
在这里插入图片描述
将上面的例子改下,我们看看结果:

private void doSomeWork() {
        Observable.mergeDelayError(Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
                observableEmitter.onNext("0");
                Thread.sleep(100);
                observableEmitter.onError(new Throwable("error"));
            }
        }).subscribeOn(Schedulers.io()), Observable.create(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
                observableEmitter.onNext("1");
                Thread.sleep(50);
                observableEmitter.onNext("3");
                Thread.sleep(50);
                observableEmitter.onNext("5");
                Thread.sleep(50);
                observableEmitter.onNext("7");
                Thread.sleep(50);
                observableEmitter.onComplete();

            }
        }).subscribeOn(Schedulers.io())).subscribe(new Observer<String>() {
            @Override
            public void onSubscribe(Disposable disposable) {

            }

            @Override
            public void onNext(String s) {
                Log.d(TAG, " onNext : s : " + s);
            }

            @Override
            public void onError(Throwable throwable) {
                Log.d(TAG, " onError : throwable : " + throwable.getMessage());
            }

            @Override
            public void onComplete() {

            }
        });
    }

打印结果

onNext : s : 0
onNext : s : 1
onNext : s : 3
onNext : s : 5
onNext : s : 7
onError : throwable : error

Zip

通过指定的功能将多个Observable的发射组合在一起,并根据此功能的结果为每个组合发出单个项目。
Zip方法返回一个Observable,它将您选择的函数按顺序应用于两个(或更多)其他Observable发出的项的组合,此函数的结果将成为返回的Observable发出的项。 它以严格的顺序应用此函数,因此新Observable发出的第一个项将是应用于Observable 1发出的第一个项的函数和Observable 2发出的第一个项的结果。 新的zip-Observable发出的第二个项目是应用于Observable 1发出的第二个项目和Observable 2发出的第二个项目的结果,以此类推。 它只会发出与发出最少项目的源Observable发出的项目数一样多的项目。
在这里插入图片描述

zip组合是按顺序一一对应的,所以zip后的项目数等于最少项目的源Observable的项目数。
举个例子,将姓名与性别组合成一个人:

public class Person {
        String name = "";
        String sex = "";

        public Person(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }
    }

    public class Name {
        String name = "";

        public Name(String name) {
            this.name = name;
        }
    }

    public class Sex {
        String sex = "";

        public Sex(String sex) {
            this.sex = sex;
        }
    }

    private void doSomeWork() {
        Observable.zip(Observable.just(new Name("张三"), new Name("李四"), new Name("王五"), new Name("赵六")),
                Observable.just(new Sex("男"), new Sex("女"), new Sex("不男不女")),
                new BiFunction<Name, Sex, Person>() {
                    @Override
                    public Person apply(Name name, Sex sex) throws Exception {
                        return new Person(name.name, sex.sex);
                    }
                }).subscribe(new Consumer<Person>() {
            @Override
            public void accept(Person person) throws Exception {
                Log.d(TAG, " accept : person : " + person.name + "," + person.sex);
            }
        });
    }

由于姓名的数目与性别的数目不相等,所以最后zip的结果应该与最小的源Observable数目相等,一一组合后,打印结果:

accept : person : 张三,男
accept : person : 李四,女
accept : person : 王五,不男不女

Join

根据另一个Observable发出的项目定义的时间窗口期间发出一个Observable中的项目时,组合两个Observable发出的项目。
Join运算符组合两个Observable发出的项目,并根据您在每个项目上定义的持续时间窗口选择要组合的项目。 您将这些窗口实现为Observables,其生命周期以Observable发出的每个项目开始。 当这样的窗口定义Observable发出项目或完成时,与其关联的项目的窗口将关闭。 只要项目的窗口打开,它就会与其他Observable发出的任何项目组合在一起。 您可以定义项目组合的功能。
在这里插入图片描述
在这里插入图片描述
join操作符其实平时基本上也没怎么用到,想理解join,先看下他的几个参数:
Observable:源Observable需要组合的Observable,这里我们姑且称之为目标Observable;
Func1:接收从源Observable发射来的数据,并返回一个Observable,这个Observable的声明周期决定了源Obsrvable发射出来的数据的有效期;
Func1:接收目标Observable发射来的数据,并返回一个Observable,这个Observable的声明周期决定了目标Obsrvable发射出来的数据的有效期;
Func2:接收从源Observable和目标Observable发射出来的数据,并将这两个数据组合后返回。

join操作符的源Observable和目标Observable他们都按照自己的节奏发射数据,发射数据的有效期由对应的Func决定。目标Observable每发射一个数据,都把它和源Observable中已经发射的未失效的数据进行一对一匹配。
举个例子:

public class Person {
        String name = "";
        String sex = "";

        public Person(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }
    }

    public class Name {
        String name = "";

        public Name(String name) {
            this.name = name;
        }
    }

    public class Sex {
        String sex = "";

        public Sex(String sex) {
            this.sex = sex;
        }
    }

    private void doSomeWork() {
        Observable.interval(50, TimeUnit.MILLISECONDS).take(4).map(new Function<Long, Name>() {
            @Override
            public Name apply(Long aLong) throws Exception {
                if (0 == aLong)
                    return new Name("张三");
                else if (1 == aLong)
                    return new Name("李四");
                else if (2 == aLong)
                    return new Name("王五");
                else
                    return new Name("赵六");
            }
        }).join(Observable.interval(50, TimeUnit.MILLISECONDS).take(3).map(new Function<Long, Sex>() {
            @Override
            public Sex apply(Long aLong) throws Exception {
                if (0 == aLong)
                    return new Sex("男");
                else if (1 == aLong)
                    return new Sex("女");
                else
                    return new Sex("不男不女");
            }
        }), new Function<Name, ObservableSource<Long>>() {
            @Override
            public ObservableSource<Long> apply(Name name) throws Exception {
                return Observable.timer(100, TimeUnit.MILLISECONDS);
            }
        }, new Function<Sex, ObservableSource<Long>>() {
            @Override
            public ObservableSource<Long> apply(Sex sex) throws Exception {
                return Observable.timer(50, TimeUnit.MILLISECONDS);
            }
        }, new BiFunction<Name, Sex, Person>() {
            @Override
            public Person apply(Name name, Sex sex) throws Exception {
                return new Person(name.name, sex.sex);
            }
        }).subscribe(new Consumer<Person>() {
            @Override
            public void accept(Person person) throws Exception {
                Log.d(TAG, " accept : person : " + person.name + "," + person.sex);
            }
        });
    }

打印结果

accept : person : 张三,男
accept : person : 李四,男
accept : person : 张三,女
accept : person : 李四,女
accept : person : 王五,女
accept : person : 张三,不男不女
accept : person : 李四,不男不女
accept : person : 王五,不男不女
accept : person : 赵六,不男不女

在这里对比下merge、zip、join这三个操作符:

操作符说明
merge合并多个Observable发出的数据 ,最终发射的数目等于源数目总和;
zip按顺序组合多个Obserable发出数据内容,最终发射的数目由最小数目的源Observable决定;
join两个源Obserable据自己的节奏不断发射数据元素,第二个数据源B,每发射一个数据,都和第一个数据源A中已经发射的未失效数据进行一对一匹配,最终发射的数目看时间情况;

CombineLatest

当一个项目由两个Observable中的任何一个发出时,通过指定的函数组合每个Observable发出的最新项目,并根据此函数的结果发出项目。
在这里插入图片描述
在这里插入图片描述
combineLatest操作符是每个源发射出后都会和另外一个源最后发出的项进行组合。如上图,A发射后,另一个源最后发出的是1,所以组合成1A;再看看3发射出去的时候,与之对应的另一源最后发出的是D,所以最后组合成的是3D。
举个例子:

public class Person {
        String name = "";
        String sex = "";

        public Person(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }
    }

    public class Name {
        String name = "";

        public Name(String name) {
            this.name = name;
        }
    }

    public class Sex {
        String sex = "";

        public Sex(String sex) {
            this.sex = sex;
        }
    }

    private void doSomeWork() {
        Observable.combineLatest(Observable.interval(20, TimeUnit.MILLISECONDS).take(4).map(new Function<Long, Name>() {
            @Override
            public Name apply(Long aLong) throws Exception {
                if (0 == aLong)
                    return new Name("张三");
                else if (1 == aLong)
                    return new Name("李四");
                else if (2 == aLong)
                    return new Name("王五");
                else
                    return new Name("赵六");
            }
        }), Observable.interval(50, TimeUnit.MILLISECONDS).take(3).map(new Function<Long, Sex>() {
            @Override
            public Sex apply(Long aLong) throws Exception {
                if (0 == aLong)
                    return new Sex("男");
                else if (1 == aLong)
                    return new Sex("女");
                else
                    return new Sex("不男不女");
            }
        }), new BiFunction<Name, Sex, Person>() {
            @Override
            public Person apply(Name name, Sex sex) throws Exception {
                return new Person(name.name, sex.sex);
            }
        }).subscribe(new Consumer<Person>() {
            @Override
            public void accept(Person person) throws Exception {
                Log.d(TAG, " accept : person : " + person.name + "," + person.sex);
            }
        });
    }

当张三发射出来的时候,第二个源还没有发射出项目,等第二个源发射出男时,第一个源已经在前发射出李四,所以第一个打印的是李四,男。打印结果:

accept : person : 李四,男
accept : person : 王五,男
accept : person : 赵六,男
accept : person : 赵六,女
accept : person : 赵六,不男不女

StartWith

在开始从源Observable中发出项之前,发出指定的项序列。
在这里插入图片描述
StartWith这个操作符比较简单,顾名思义就是在发射源项目前先发射with中的项目。如果需要在前发射多个项目用startWithArray操作符即可。另一方面,如果要将一系列项追加到源发出的项的末尾,则需要Concat运算符。
举个例子:

private void doSomeWork() {
        Observable.range(0, 3)
                .startWith(-1)
                .subscribe(new Consumer<Integer>() {
                    @Override
                    public void accept(Integer integer) throws Exception {
                        Log.d(TAG, " accept : integer : " + integer);
                    }
                });
    }

打印结果

accept : integer : -1
accept : integer : 0
accept : integer : 1
accept : integer : 2

参考资料,参考但不局限以下链接
http://reactivex.io/documentation/operators.html#transforming
https://blog.csdn.net/peaty34/article/details/52247784
https://www.jianshu.com/p/546fe44a6e22

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值