RxJava操作符系列四

RxJava

RxJava操作符系列传送门

RxJava操作符源码
RxJava操作符系列一
RxJava操作符系列二
RxJava操作符系列三

前言

在上一篇文章我们主要介绍的是RxJava的一些过滤操作符,若将过滤操作和转换操作一起使用,能处理复杂的的业务逻辑,在文章中所举的例子都是都是很简单的逻辑,简单的让人感觉这样写没必要,当然这这是为了便于理解操作符的含义,只有理解了这些基础上我们才能做更复杂的操作。相信通过学习,能感悟出RxJava的强大。让我们继续开启学习之旅吧。

Merge

该操作符可以将多个Observables的输出合并,就好像它们是一个单个的Observable一样,他可能让我们让合并的Observables发射的数据交错(顺序发生变化),在此过程中任何一个原始Observable的onError通知都会被立即传递给观察者,而且会终止合并后的Observable。

        Observable observable=Observable.just(1,2);
        Observable observable1=Observable.just(6,7);
        Observable.merge(observable, observable1)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: ");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: "+e.toString() );
                    }

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

输出日志信息

onNext: 1
onNext: 2
onNext: 6
onNext: 7
onCompleted: 

如果我们此时在创建一个Obserable如下

        Observable observable2 = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {
                try {
                    Thread.sleep(500);
                    subscriber.onNext(200);
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).subscribeOn(Schedulers.newThread());

然后将merge(observable, observable1)更改为merge(observable2,observable, observable1)
再次执行,发现虽然observable2是第一个参数,但是输出却是在最后一个输出。

MergeDelayError

对于merge操作符的任何一个的Observable发射了onError通知终止了,merge操作符生成的Observable也会立即以onError通知终止。如果你想让它继续发射数据,在最后才报告错误,可以使用mergeDelayError。我们先使用merge将observable2的创建代码更改下面代码,依然执行merge(observable2,observable, observable1)。

        Observable observable2 = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

               try {
                    subscriber.onNext(100);
                    subscriber.onError(new Throwable("error"));
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    subscriber.onError(new Throwable("error11"));
                }

            }
        }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());

输出日志信息

onError: java.lang.Throwable: error

由于observable2 的异常,导致observable和 observable1被中断。
那么如果在这种情况下依然发送数据该怎么办呢,MergeDelayError就可以达到这样的效果,看如下实现代码。最后提醒下MergeDelayError的使用有个坑,就是subscribeOn和observeOn的调用问题,如果先mergeDelayError之后再用subscribeOn和observeOn指定调度器发现该操作符并不起作用。需要在单独创建Observable时使用,如下示例代码

        Observable observable = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

               try {
                    subscriber.onNext(100);
                    subscriber.onError(new Throwable("error"));
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    subscriber.onError(new Throwable("error11"));
                }

            }
        }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());
        Observable observable3=Observable.just(6,7,8,9).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());
        Observable.merge(observable,observable1)
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: ");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: "+e.toString() );
                    }

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

输出日志信息

onNext: 6
onNext: 7
onNext: 8
onNext: 9
onError: java.lang.Throwable: error

Concat

该操作符和merge操作符相似,不同之处就是该操作符按顺序一个接着一个发射多个Observables的发射物。保证顺序性。

Observable observableA = Observable.create(new Observable.OnSubscribe<Integer>() {
            @Override
            public void call(Subscriber<? super Integer> subscriber) {

                try {
                    subscriber.onNext(100);
                    Thread.sleep(500);
                    subscriber.onNext(200);
                    subscriber.onCompleted();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    subscriber.onError(new Throwable("error11"));
                }
            }
  }).subscribeOn(Schedulers.newThread()).observeOn(AndroidSchedulers.mainThread());
        Observable<Integer> observableB = Observable.range(7, 2);
        Observable.concat(observableA, observableB).subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: concat");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: concat");
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG, "onNext: concat" + integer);
            }
        });

输出日志信息

onNext: concat100
onNext: concat200
onNext: concat7
onNext: concat8
onCompleted: concat

这样就保证了顺序性,如果用merge的话,100和200应该在7和8后输出。

Zip

该操作符返回一个Obversable,它使用这个函数按顺序结合两个或多个Observables发射的数据项,然后它发射这个函数返回的结果。它按照严格的顺序应用这个函数。它只发射与发射数据项最少的那个Observable一样多的数据,假如两个Observable数据分布为4项,5项,则最终合并是4项。如下示例代码

List<String> names = new ArrayList<>();
        List<Integer> ages = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            names.add("张三" + i);
            ages.add(20 + i);
        }
        ages.add(15);
        Observable observable1 = Observable.from(names).subscribeOn(Schedulers.io());
        Observable observable2 = Observable.from(ages).subscribeOn(Schedulers.io());
        //Func2第三个参数是返回值类型
        Observable.zip(observable1, observable2, new Func2<String, Integer, String>() {
            @Override
            public String call(String name, Integer age) {
                return name + ": " + age;
            }
        }).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber<String>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: ");
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: ");
            }

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

输出日志信息

onNext: 张三0: 20
onNext: 张三1: 21
onNext: 张三2: 22
onNext: 张三3: 23
onNext: 张三4: 24
onCompleted: 

StartWith

该操作符作用是在一个Observable在发射数据之前先发射一个指定的数据序列。如下

Observable.range(1,3).startWith(11,12).subscribe(new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: " );
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: ");
            }

            @Override
            public void onNext(Integer integer) {
                Log.e(TAG, "onNext: "+integer );
            }
        });

输出日志信息

onNext: 11
onNext: 12
onNext: 1
onNext: 2
onNext: 3
onCompleted: 

CombineLatest

这里写图片描述

操作符行为类似于zip,但是只有当原始的Observable中的每一个都发射了一条数据时zip才发射数据。CombineLatest则在原始的Observable中任意一个发射了数据时发射一条数据。当原始Observables的任何一个发射了一条数据时,CombineLatest使用一个函数结合它们最近发射的数据,然后发射这个函数的返回值。通过上面的图应该更容易理解。
示例代码

 Observable<Integer> observableA = Observable.range(1, 4);
        Observable<Integer> observableB = Observable.range(10, 5);
        Observable.combineLatest(observableA, observableB, new Func2<Integer, Integer, String>() {
            @Override
            public String call(Integer integer, Integer integer2) {
                Log.e(TAG, "call: combineLatest");
                return "observableA:" + integer + "  observableB:" + integer2;
            }
        }).subscribe(new Action1<String>() {
            @Override
            public void call(String s) {
                Log.e(TAG, "call: combineLatest" + s);
            }
        });

输出日志信息

call: combineLatest
call: combineLatestobservableA:4  observableB:10
call: combineLatest
call: combineLatestobservableA:4  observableB:11
call: combineLatest
call: combineLatestobservableA:4  observableB:12
call: combineLatest
call: combineLatestobservableA:4  observableB:13
call: combineLatest
call: combineLatestobservableA:4  observableB:14

Join

该操作符只要在另一个Observable发射的数据定义的时间窗口内,这个Observable发射了一条数据,就结合两个Observable发射的数据.例如A作为基础窗口,当A发射了数据1,2,3,4,5时,B发射了一个数据a.则此时合并数据(1,a),(2,a),(3,a),(4,a),(5,a),此时将窗口清楚并重新打开一个窗口循环此种操作直到数据输出完毕。
示例代码

Observable<Integer> observableA = Observable.range(1, 2).subscribeOn(Schedulers.newThread());
        Observable<Integer> observableB = Observable.range(7, 3).subscribeOn(Schedulers.newThread());
        observableA.join(observableB, new Func1<Integer, Observable<Integer>>() {
            @Override
            public Observable<Integer> call(Integer integer) {
                Log.e(TAG, "call: A" + integer +"   "+ Thread.currentThread().getName());
                return Observable.just(integer).delay(1,TimeUnit.SECONDS);
            }
        }, new Func1<Integer, Observable<Integer>>() {
            @Override
            public Observable<Integer> call(Integer integer) {
                Log.e(TAG, "call: B" + integer +"   "+ Thread.currentThread().getName());
                return Observable.just(integer).delay(1,TimeUnit.SECONDS);
            }
        }, new Func2<Integer, Integer, Integer>() {
            @Override
            public Integer call(Integer integer, Integer integer2) {
                Log.e(TAG, "call:AjoinB A: " + integer + " B:" + integer2 + Thread.currentThread().getName());
                return integer+integer2;
            }
        }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<Integer>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: ");
                    }

                    @Override
                    public void onError(Throwable e) {
                        Log.e(TAG, "onError: "+e.toString());
                    }

                    @Override
                    public void onNext(Integer integer) {
                        Log.e(TAG, "onNext: "+integer);
                    }
                });

输出日志信息

call: A1   RxNewThreadScheduler-4
call: A2   RxNewThreadScheduler-4
call: B7   RxNewThreadScheduler-5
call:AjoinB A: 1 B:7RxNewThreadScheduler-5
call:AjoinB A: 2 B:7RxNewThreadScheduler-5
call: B8   RxNewThreadScheduler-5
call:AjoinB A: 1 B:8RxNewThreadScheduler-5
call:AjoinB A: 2 B:8RxNewThreadScheduler-5
call: B9   RxNewThreadScheduler-5
onNext: 8
onNext: 9
onNext: 9
call:AjoinB A: 1 B:9RxNewThreadScheduler-5
call:AjoinB A: 2 B:9RxNewThreadScheduler-5
onNext: 10
onNext: 10
onNext: 11
onCompleted: 

switchOnNext

这里写图片描述

该操作符将一个发射多个Observables的Observable转换成另一个单独的Observable,后者发射那些Observables最近发射的数据项。当有新的Observable开始订阅时,会取消之前的订阅,并将数据丢弃。如下示例

        Observable<Observable<Long>> observable = Observable.interval(0, 500, TimeUnit.MILLISECONDS).map(new Func1<Long, Observable<Long>>() {
            @Override
            public Observable<Long> call(Long aLong) {
                //每隔200毫秒产生一组数据(0,10,20,30,40)
                Log.e(TAG, "call1: "+aLong);
                return Observable.interval(0, 200, TimeUnit.MILLISECONDS).map(new Func1<Long, Long>() {
                    @Override
                    public Long call(Long aLong) {
                        Log.e(TAG, "call2: "+aLong );
                        return aLong * 10;
                    }
                }).take(5);
            }
        }).take(2);
        Observable.switchOnNext(observable).subscribe(new Subscriber<Long>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted: SwitchOnNext" );
            }

            @Override
            public void onError(Throwable e) {
                Log.e(TAG, "onError: SwitchOnNext");
            }

            @Override
            public void onNext(Long aLong) {
                Log.e(TAG, "onNext: SwitchOnNext  "+aLong);
            }
        });

输出日志信息

call1: 0
call2: 0
onNext: SwitchOnNext  0
call2: 1
onNext: SwitchOnNext  10
call2: 2
onNext: SwitchOnNext  20
call1: 1
call2: 0
onNext: SwitchOnNext  0
call2: 1
onNext: SwitchOnNext  10
call2: 2
onNext: SwitchOnNext  20
call2: 3
onNext: SwitchOnNext  30
call2: 4
onNext: SwitchOnNext  40
onCompleted: SwitchOnNext

今天的这篇文章就到此结束,欢迎大家阅读,若发现文中有错误的地方欢迎留言提出,感谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容