RxJava操作符系列一

detail.jpg

前言

第一次接触学习RxJava应该是一两个月前的事情了,但其中也是断断续续,最近又再次去学习RxJava,和当初刚接触RxJava完全不是同样的心情,轻松了很多,也感受到了RxJava的魅力,真是不由衷感叹太牛了。目前关于RxJava的文章也很多,个人推荐两篇扔物线的给 Android 开发者的 RxJava 详解和大头鬼Bruce的译文 深入浅出RxJava系列。那么这篇文章通过代码介绍RxJava中的操作符,以及操作符的使用。当然操作符较多,准备分几篇文章介绍。如果你想提前学习其他操作符可以去GitHub,欢迎star项目。


RxJava操作符源码传送门


基础介绍

为了力求有没有RxJava基础都能看懂此文,简单介绍一下RxJava以及一些名词。在RxJava开源的Github上是这样解释的a library for composing asynchronous and event-based programs using observable sequences for the Java VM。无论多么复杂的逻辑,都可以保持整洁的代码格式。

在RxJava中最重要的就是Observable(被观察者),subscribe(订阅),Observer(观察者)或者Subscriber(订阅者),Observable也就是数据(事件)源,Subscriber负责接收以及处理数据(事件)。当然要想实现两者通信,需要有一种机制那就是订阅。Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。

例如张三(观察者)想看某款新闻软件的科技信息(被观察者),由于科技信息是每天推送或者不定时推送,如果张三一直盯着手机屏幕看并且刷新消息是不是又新的信息,显然不现实。这时候就可以通过张三 subscribe(订阅)科技信息,而实现当有新的科技信息时自动给张三推送消息,在这期间,张三并不需要一直盯着屏幕刷新闻。在我们平时的认知中实现订阅应该是张三.subscribe(科技新闻),不过在RxJava代码中实现订阅应该写成科技新闻.subscribe(张三)。

在RxJava中,有三个事件回调方法,分别是onNext(),OnError(),onCompleted(),onNext()是最终输出及处理数据的回调,在发射数据过程中出现错误异常会回调OnError()方法,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。,OnError()和onCompleted()是互斥的。下面举一个最简单的例子

        Observable observable2 = Observable.just("也许当初忙着微笑和哭泣", "忙着追逐天空中的流星", "人理所当然的忘记", "是谁风里雨里一直默默守护在原地");
        Subscriber subscriber = 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 s) {
               Log.e(TAG, "onNext: "+s )
            }
        };
        observable.subscribe(subscriber);

运行后打印信息为

onNext: 也许当初忙着微笑和哭泣
onNext: 忙着追逐天空中的流星
onNext: 人理所当然的忘记
onNext: 是谁风里雨里一直默默守护在原地
onCompleted: 

Create

我们可以使用该操作符从零开始创建一个Observable,给这个操作符传递一个接受观察者作为参数的函数,并调用观察者的onNext,onError和onCompleted方法。如下

        //被观察者
        Observable<String> observable = Observable.create(new Observable.OnSubscribe<String>() {
            @Override
            public void call(Subscriber<? super String> subscriber) {
                //可以多次调用subscriber.onNext("大家好")发射数据
                subscriber.onNext("大家好");
                subscriber.onNext("我开始学习RxJava");
                subscriber.onCompleted();

            }
        });

发送数据需要在毁掉方法call中调用subscriber的onNext(),onNext(T)发送的参数需要和Observable.OnSubscribe<T>()中参数相同,在上面我们传入的是String类型。创建后Observale后,我们需要创建Subscriber(观察者)去处理observable发送的数据。如下

        Subscriber<String> subscriber = new Subscriber<String>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.e(TAG, e.getMessage());
            }
            @Override
            public void onNext(String s) {
                Log.e(TAG, "onNext:"+s);
            }
        };

数据成功发送后,会回调Subscriber的onNext()的方法,其中的参数就是接收到的数据。当onNext()接收数据完毕后会执行onCompleted(),如果中途有环节出现错误异常,会执行onError()。现在观察者和被观察者都创建完毕了,他们执行还需要一个前提就是订阅,如果不订阅,observable并不会发射数据,subscribe也不会接收数据,订阅代码如下

observable.subscribe(subscriber);

执行后输出信息

onNext:大家好
onNext:我开始学习RxJava
onCompleted

from

该操作符是将其它种类的对象和数据类型转换为Observable,如果当你发射的的数据是同一种类型,而不是混合使用Observables和其它类型的数据,会非常方便。如下创建Observable

        Integer[] integers = {1,2, 3, 4};
        Observable<Integer> observable=Observable.from(integers);
         Subscriber<String> subscriber = new Subscriber<Integer>() {
            @Override
            public void onCompleted() {
                Log.e(TAG, "onCompleted");
            }
            @Override
            public void onError(Throwable e) {
                Log.e(TAG, e.getMessage());
            }
            @Override
            public void onNext(Integer i) {
                Log.e(TAG, "onNext:"+i);
            }
        };
        observable.subscribe(subscriber);
        

输出信息为

onNext:1
onNext:2
onNext:3
onNext:4
onCompleted

from操作符可以转换Future、Iterable和数组。对于Iterable和数组,产生的Observable会发射Iterable或数组的每一项数据。对于Future,它会发射Future.get()方法返回的单个数据,并且还可以增加通过: from(Future,timeout, timeUnit)指定超时时间,如果执行的时候Future超时会回调onError()方法。

just

just将单个数据转换为发射那个数据的Observable,Just类似于From,但是From会将数组或Iterable的数据取出然后逐个发射,而Just只是简单的原样发射,将数组或Iterable当做单个数据,如果你传递null给Just,它会返回一个发射null值的Observable。不要误认为它会返回一个空Observable(完全不发射任何数据的Observable)。对于just可以接收1到10个数据,返回一个按参数列表顺序发射这些数据的Observable。

        Observable.just(1 2, 3, 4)
                .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:1
onNext:2
onNext:3
onNext:4
onCompleted:

对于just参数类型可以是多种,如下,传入两个类型数据

Observable.just(0, "one", 6, "two", 8, "three")
                .subscribe(new Subscriber<Serializable>() {
                    @Override
                    public void onCompleted() {
                        Log.e(TAG, "onCompleted: " );
                    }

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

                    @Override
                    public void onNext(Serializable serializable) {
                        Log.e(TAG, "onNext: "+serializable.toString());
                    }
                });

则输出信息

onNext:0
onNext:one
onNext:6
onNext:two
onNext:8
onNext:three
onCompleted:

Empty/Never/Error

Empty:创建一个不发射任何数据但是正常终止的Observable,此时会回调onCompleted()

Never:创建一个不发射数据也不终止的Observable

Error:创建一个不发射数据以一个错误终止的Observable

error操作符需要一个Throwable参数,你的Observable会以此终止。这些操作符默认不在任何特定的调度器上执行,但是empty和error有一个可选参数是Scheduler,如果你传递了Scheduler参数,它们会在你指定的调度器上发送通知。

Range

该操作符创建特定整数序列的Observable,它接受两个参数,一个是范围的起始值,一个是范围的数据的数目。如果你将第二个参数设为0,将导致Observable不发射任何数据(如果设置为负数,会抛异常)。

        Observable.range(1,4)
                .subscribe(new Subscriber<Integer>() {
                    public String TAG="RXJAVA";

                    @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: 1
onNext: 2
onNext: 3
onNext: 4
onCompleted: 

你可以在代码实战中,更改第二个参数为负数,或者0,以及将第一个参数更改为你想测试的任意值,去观察执行日志帮助理解。

Timer

Timer操作符创建一个在给定的时间段之后返回一个特殊值的Observable。它在延迟一段给定的时间后发射一个简单的数字0 。

Observable.timer(1, TimeUnit.SECONDS)
                .subscribe(new Subscriber<Long>() {
                    public String TAG="RXJAVA";

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

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

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

对于该操作符默认在computation调度器上执行的,如果你想在onNext()回调方法更新UI,需要通过observeOn(AndroidSchedulers.mainThread())设置,否则会调用onError()方法。当然Time人提供的有一个三个参数的方法timer(long,TimeUnit,Scheduler)可以指定 Scheduler 。

Interval

该操作符按固定的时间间隔发射一个无限递增的整数序列,它接受一个表示时间间隔的参数和一个表示时间单位的参数,当然该操作符合Timer一样,是在computation调度器上执行的,若想更新UI需要指定Scheduler 为AndroidSchedulers.mainThread()。

     Subscription   subscription = Observable.interval(1, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Long>() {
                    @Override
                    public void call(Long aLong) {
                        tv.append(" " + aLong + "   ");
                    }
                });

通过上面代码就会每隔1秒在tv上追加一个数字,并且会永远执行。如果在某个时刻不想继续输出,就需要要解除订阅。

        if (subscription != null && !subscription.isUnsubscribed()) {
            subscription.unsubscribe();
        }

Repeat

该操作符是重复的发射某个数据序列,并且可以自己设置重复的次数。当接收到onComplete()会触发重订阅再次重复发射数据,当重复发射数据次数到达后执行onCompleted()。

        String[] strs = {"也许当初忙着微笑和哭泣", "忙着追逐天空中的流星"};
        Observable.from(strs).repeat(2)..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 s) {
                Log.e(TAG, "onNext: "+s );
                tv1.append("\n" + s);
            }
        });

输出

onNext: 也许当初忙着微笑和哭泣
onNext: 忙着追逐天空中的流星
onNext: 也许当初忙着微笑和哭泣
onNext: 忙着追逐天空中的流星
onCompleted: 

Defer

直到有观察者订阅时才创建Observable,并且为每个观察者创建一个新的Observable,该操作符能保证订阅执行时数据源是最新的数据。如下正常代码

        String test="旧数据";
        Observable observable=Observable.just(test);
        Subscriber subscriber=new Subscriber() {
            public String TAG="RXJAVA";

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

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

            @Override
            public void onNext(Object o) {
                Log.e(TAG, "onNext: "+o );
            }
        };
        test="新数据";
        observable.subscribe(subscriber);

输出

 onNext: 旧数据
 onCompleted: 

通过上面代码和输出日志发现,虽然在后面讲数据test更新为新数据,但是并没有生效,要想使用最新的数据就需要使用defer操作符。此时更改使用defer

        test="旧数据";
        Observable<String> observable=Observable.defer(new Func0<Observable<String>>() {
            @Override
            public Observable<String> call() {
                return Observable.just(test);
            }
        });
        Subscriber subscriber=new Subscriber() {
            public String TAG="RXJAVA";

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

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

            @Override
            public void onNext(Object o) {
                Log.e(TAG, "onNext: "+o );
            }
        };
        test="新数据";
        observable.subscribe(subscriber);

输出信息

onNext: 新数据
onCompleted: 

通过新的打印信息,发现输出值已经是最新的数据。

到这里,这篇文章暂时就先结束了,若文章有不足或者错误的地方,欢迎指正,以防止给其他读者错误引导。更多的操作符,将在接下来的几篇文章介绍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • 本篇文章介主要绍RxJava中操作符是以函数作为基本单位,与响应式编程作为结合使用的,对什么是操作、操作符都有哪些...
    嘎啦果安卓兽阅读 2,780评论 0 10
  • 注:只包含标准包中的操作符,用于个人学习及备忘参考博客:http://blog.csdn.net/maplejaw...
    小白要超神阅读 2,142评论 2 8
  • 作者: maplejaw本篇只解析标准包中的操作符。对于扩展包,由于使用率较低,如有需求,请读者自行查阅文档。 创...
    maplejaw_阅读 45,326评论 8 93
  • 创建操作 用于创建Observable的操作符Create通过调用观察者的方法从头创建一个ObservableEm...
    rkua阅读 1,446评论 0 1
  • 注:本系列文章主要用于博主个人学习记录,本文末尾附上了一些较好的文章提供学习。转载请附 原文链接RxJava学习系...
    黑丫山上小旋风阅读 2,079评论 1 5