RxAndroid使用文档(New)
来源:互联网 发布:roadflow最新源码下载 编辑:程序博客网 时间:2024/06/07 16:05
1 概述
RxJava 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库.响应式编程是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。
Rx并不是一种新的语言,而是一种普通的Java模式,类似于观察者模式(Observer Pattern),可以将它看作一个普通的Java类库。而RxAndroid是RxJava的一个针对Android平台的扩展,主要用于 Android 开发。
1.1 RxJava 有几个基本概念:
- Observable 发射源 (可观察者,即被观察者)
- Observer 接收源(观察者)
- Subscriber:Subscriber实现了Observer和Subscription接口,所以比Observer多了一个方法unsubscribe( ),用来取消订阅。
- Subject:一个比较特殊的对象,既可充当发射源,也可充当接收源
- Subscription :Observable调用subscribe( )方法返回的对象,同样有unsubscribe()方法,可以用来取消订阅事件;
- Action0:RxJava中的一个接口,它只有一个无参call()方法,且无返回值,同样还有Action1,Action2…Action9等,Action1封装了含有 1 个参的call()方法,即call(T t),Action2封装了含有 2 个参数的call方法,即call(T1 t1,T2 t2),以此类推;
- Func0:与Action0非常相似,也有call()方法,但是它是有返回值的,同样也有Func0、Func1…Func9;
- subscribe() 订阅方法,subscribe() 之后, Observable 会持有 Subscriber 的引用,这个引用如果不能及时被释放,将有内存泄露的风险。
- unsubscribe() 取消订阅方法,在这个方法被调用后,Subscriber 将不再接收事件。要在不再使用的时候尽快在合适的地方(例如 onPause() onStop() 等方法中)调用 unsubscribe() 来解除引用关系,以避免内存泄露的发生。
Observable 和 Observer 通过 subscribe() 方法实现订阅关系,从而 Observable 可以在需要的时候发出事件来通知 Observer。
1.2 RxJava的优点
- 创建:Rx可以方便的创建事件流和数据流
- 组合:Rx使用查询式的操作符组合和变换数据流
- 监听:Rx可以订阅任何可观察的数据流并执行操作
- 函数式风格:对可观察数据流使用无副作用的输入输出函数,避免了程序里错综复杂的状态
- 简化代码:Rx的操作符通通常可以将复杂的难题简化为很少的几行代码
- 异步错误处理:传统的try/catch没办法处理异步计算,Rx提供了合适的错误处理机制
- 轻松使用并发:Rx的Observables和Schedulers让开发者可以摆脱底层的线程同步和各种并发问题
2 Observable
Observable 即被观察者,它决定什么时候触发事件以及触发怎样的事件。
一个Observable可以发出零个或者多个事件,直到结束或者出错。每发出一个事件,就会调用它subscribe的Subscriber的onNext方法,最后调用Subscriber.onCompleted()完成或者Subscriber.onError()出错而结束。
下面看看RxJava提供的创建Observable的方法:
2.1 create
新建一个Observables.create方法中传入了一个 OnSubscribe 对象作为参数,OnSubscribe 会被存储在返回的 Observable 对象中,它的作用相当于一个计划表。当 Observable 被订阅(subscribe)的时候,OnSubscribe 的 call() 方法会自动被调用,事件序列就会依照call中设定依次触发.
public void testCreate(View view) { mObservable = Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { if (!subscriber.isUnsubscribed()) { subscriber.onNext("Hello"); subscriber.onNext("World"); subscriber.onCompleted(); } } });}
2.1 subscribe()订阅
由于创建后需要订阅了才能看到效果,这里初步看看订阅方法。subscribe()注册 Subscriber
到 Observable
.
subscribe()方法做了三件事:
- 调用 Subscriber.onStart()
- 调用 Observable 中的 OnSubscribe.call(Subscriber)
- 将传入的 Subscriber 作为 Subscription 返回
public void testSubscribe(View view) { if (mObservable != null) { mObservable.subscribe(new Subscriber<String>() { @Override public void onStart() { /** start方法不是必须的,call方法之前调用。 * 在subscribe 所发生的线程被调用,不能指定线程 */ Log.e("testSubscribe", "onStart" + Thread.currentThread().getId()); super.onStart(); } @Override public void onCompleted() { Log.e("testSubscribe", "onCompleted" + Thread.currentThread().getId()); } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(String s) { Log.e("testSubscribe", s + Thread.currentThread().getId()); } }); }}
2.2 forEach
forEach方法是简化版的subscribe,无返回值。通过 forEach 可以处理 Observable 每个发射出来的数据。且是非阻塞执行的。forEach一般用于遍历所有元素,然后处理。
public void forEach(View v) { Observable.interval(500, TimeUnit.MILLISECONDS) .take(6) .forEach(LogUtils::e); LogUtils.e("over");}
非阻塞的,所以先打印出后面的内容。
02-18 00:50:16.921 15095-15095/com.felix.testrxjava E/LogUtils: over02-18 00:50:17.420 15095-15290/com.felix.testrxjava E/LogUtils: 002-18 00:50:17.920 15095-15290/com.felix.testrxjava E/LogUtils: 102-18 00:50:18.420 15095-15290/com.felix.testrxjava E/LogUtils: 202-18 00:50:18.919 15095-15290/com.felix.testrxjava E/LogUtils: 302-18 00:50:19.420 15095-15290/com.felix.testrxjava E/LogUtils: 402-18 00:50:19.919 15095-15290/com.felix.testrxjava E/LogUtils: 5
2.3 just(T…)
just()方法可以传入一到九个参数,它们会按照传入的参数的顺序来发射它们。just()方法也可以接受列表或数组,它将会发射整个列表。通常,当我们想发射一组已经定义好的值时会用到它。但是如果我们的函数不是时变性的,我们可以用just来创建一个更有组织性和可测性的代码库。
public void testJust(View view) { mObservable = Observable.just("hello", "World"); }
2.4 from(T[] t) / from(Iterable
Observable.from(Executors.newFixedThreadPool(3).submit(new Callable<String>() { @Override public String call() throws Exception { Thread.sleep(5000); return "result"; } })) .subscribe(new Action1<String>() { @Override public void call(String s) { Log.e("", s); } });}
2.5 defer(Func0
public void testDefer(View view) { count = 1; //just方法 Observable<Integer> justObservable = Observable.just(count); count = 2; //just的订阅 justObservable.subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("testDefer", "just " + integer); } }); count = 3; //defer方法 Observable<Integer> testDefer = Observable.defer(new Func0<Observable<Integer>>() { @Override public Observable<Integer> call() { //注意此处的call方法没有Subscriber参数 return Observable.just(count); } }); count = 4; //defer订阅 testDefer.subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { Log.e("testDefer", "onCompleted"); } @Override public void onError(Throwable e) { Log.e("testDefer", "onError " + e.getMessage()); } @Override public void onNext(Integer i) { Log.e("testDefer", "defer " + i); } }); count = 5; //defer订阅2 testDefer.subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("testDefer", "Action1 defer " + integer); } });}
以上示例将just和defer放在一起做了一个对比。我们看看打印的值。just等操作符是在创建的时候就已经生成了Observable,而defer是在subscribe的时候才创建,而且每次订阅都会新创建一个,以保证当前使用的是最新的值。
com.felix.testrxjava E/testDefer: just 1com.felix.testrxjava E/testDefer: defer 4com.felix.testrxjava E/testDefer: onCompletedcom.felix.testrxjava E/testDefer: Action1 defer 5
2.6 interval/timeInterval
interval创建一个按固定时间间隔发射整数序列的Observable,可用作定时器.interval()有一个三个参数的重载方法,可以传入Scheduler调度器,默认使用的是Schedulers.computation()。
public void testInterval(View view) { //每隔2s发送一次 final Subscription subscription = Observable.interval(2, TimeUnit.SECONDS) .subscribe(new Action1<Long>() { @Override public void call(Long aLong) { Log.e("testInterval", " " + aLong); } }); //延迟15s取消订阅 new Handler().postDelayed(new Runnable() { @Override public void run() { subscription.unsubscribe(); } }, 15 * 1000);}
timeInterval将原始Observable转换为另一个Obserervable,后者发射一个标志替换前者的数据项,这个标志表示前者的两个连续发射物之间流逝的时间长度。新的Observable的第一个发射物表示的是在观察者订阅原始Observable到原始Observable发射它的第一项数据之间流逝的时间长度。不存在与原始Observable发射最后一项数据和发射onCompleted通知之间时长对应的发射物。timeInterval默认在immediate调度器上执行,你可以通过传参数修改。
public void timeInterval(View view) { Observable.create(subscriber -> { for (int i = 0; i < 5; i++) { SystemClock.sleep(i * 1000); subscriber.onNext("aaaa " + i); } subscriber.onCompleted(); }).timeInterval().cast(TimeInterval.class) .subscribe(x -> Log.e("timeInterval", x.getIntervalInMilliseconds() + "++" + x.getValue()));}
看看输出,getIntervalInMilliseconds,返回的间隔的毫秒值,getValue返回的是上一个Observable抛出来的值。
02-16 22:47:03.748 21569-21569/com.felix.testrxjava E/timeInterval: 0++aaaa 002-16 22:47:04.749 21569-21569/com.felix.testrxjava E/timeInterval: 1001++aaaa 102-16 22:47:06.749 21569-21569/com.felix.testrxjava E/timeInterval: 2000++aaaa 202-16 22:47:09.750 21569-21569/com.felix.testrxjava E/timeInterval: 3001++aaaa 302-16 22:47:13.750 21569-21569/com.felix.testrxjava E/timeInterval: 4000++aaaa 4
2.7 range
创建一个发射特定整数序列的Observable:第一个参数为起始值;第二个为发送的个数,如果为0则不发送,负数则抛异常,大于int类型的最大值也会抛异常。
/** * 发射从1开始的10个数字 * * @param view */public void testRange(View view) { Observable.range(1, 10) .subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("testRange", " " + integer); } });}
2.8 timer
创建一个Observable,它在一个给定的延迟后发射一个特殊的值(一般是0),等同于Android中Handler的postDelay()。
timer()有一个三个参数的重载方法,可以传入Scheduler调度器,默认使用的是Schedulers.computation()。
public void testTimer(View view) { Observable.timer(2, TimeUnit.SECONDS) .subscribe(new Action1<Long>() { @Override public void call(Long aLong) { Log.e("testRange", " " + aLong); } });}
2.9 repeat
创建重复发射特定的数据或数据序列的Observable
2.10 start
它接受一个函数作为参数,调用这个函数获取一个值,然后返回一个会发射这个值给后续观察者的Observable。Start操作符的多种RxJava实现都属于可选的rxjava-async模块。
注意:这个函数只会被执行一次,即使多个观察者订阅这个返回的Observable。
2.11 empty
不调用onNext(),直接调用onComplete(),这里onStart方法也会调用。
public void testEmpty(View view) { mObservable = Observable.empty();}
2.12 never
创建一个不发射数据并且也永远不会结束的Observable。只有onStart方法也会被调用。
public void testNever(View view) { mObservable = Observable.never(); mObservable.subscribe(new Subscriber<String>() { @Override public void onStart() { Log.e("testNever", "onStart"); } @Override public void onCompleted() { Log.e("testNever", "onCompleted"); } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(String s) { Log.e("testNever", "onNext " + s); } });}
2.13 error
创建一个不发射数据并且以错误结束的Observable。 只会回调onStart和onError方法。
public void testError(View view) { mObservable = Observable.error(new Exception("error test"));}
2.14 using
using操作符让你可以指示Observable创建一个只在它的生命周期内存在的资源,当Observable终止时这个资源会被自动释放。
using操作符接受三个参数:
- Func0,一个用户创建一次性资源的工厂函数
- Func1,一个用于创建Observable的工厂函数
- Action1,一个用于释放资源的函数
当一个观察者订阅using返回的Observable时,using将会使用Observable工厂函数创建观察者要观察的Observable,同时使用资源工厂函数创建一个你想要创建的资源。当观察者取消订阅这个Observable时,或者当观察者终止时(无论是正常终止还是因错误而终止),using使用第三个函数释放它创建的资源。
我们来看一个例子
public void using(View view) { Observable.using( () -> new TestUsingThread(), t -> Observable.timer(10, TimeUnit.SECONDS), resource -> resource.stopThread() ).subscribe( LogUtils::e, e -> e.printStackTrace(), () -> LogUtils.e("completed") );}class TestUsingThread extends Thread { private volatile boolean flag = true; int index = 0; public void stopThread() { this.flag = false; } public TestUsingThread() { this.start(); } @Override public void run() { while (flag) { Log.e("=====", index++ + ""); SystemClock.sleep(index * 1000); } }}
测试线程一直运行,知道时间达到10s,调用关闭方法关闭线程,这里看到线程停止运行了。用来关闭资源很好
02-18 00:39:46.087 29094-29417/com.felix.testrxjava E/=====: 002-18 00:39:47.088 29094-29417/com.felix.testrxjava E/=====: 102-18 00:39:49.088 29094-29417/com.felix.testrxjava E/=====: 202-18 00:39:52.088 29094-29417/com.felix.testrxjava E/=====: 302-18 00:39:56.090 29094-29417/com.felix.testrxjava E/=====: 402-18 00:39:56.103 29094-29419/com.felix.testrxjava E/LogUtils: 002-18 00:39:56.104 29094-29419/com.felix.testrxjava E/LogUtils: completed
3 Single
Single类似于Observable,不同的是,它总是只发射一个值,或者一个错误通知,而不是发射一系列的值。订阅Single只需要如下两个方法, 需要注意Single是没有onStart
方法.
onSuccess - Single发射单个的值到这个方法.onError - 如果无法发射需要的值,Single发射一个Throwable对象到这个方法
3.1 创建
Single的创建方式和Observable基本类似,Observable支持的方法,Single基本都支持。
使用示例如下:
public void testSingle(View view) { Single<String> single = Single.create(new Single.OnSubscribe<String>() { @Override public void call(SingleSubscriber<? super String> singleSubscriber) { if (!singleSubscriber.isUnsubscribed()) { if (SystemClock.currentThreadTimeMillis() % 2 == 0) { singleSubscriber.onSuccess("Hello"); singleSubscriber.onSuccess("World"); } else { singleSubscriber.onError(new Exception("sth error")); } } } }); single.subscribe(new SingleSubscriber<String>() { @Override public void onSuccess(String value) { Log.e("###", value); } @Override public void onError(Throwable error) { error.printStackTrace(); } });}
3.2 concatWith: Single转化为Observable
4 Observer
Observer 即观察者,它决定事件触发的时候将有怎样的行为。
Observer 是一个接口,包含了三个方法
onNext() 普通事件的回调。
onCompleted(): 事件队列完结。RxJava 不仅把每个事件单独处理,还会把它们看做一个队列。RxJava 规定,当不会再有新的 onNext() 发出时,需要触发 onCompleted() 方法作为标志。
onError(): 事件队列异常。在事件处理过程中出异常时,onError() 会被触发,同时队列自动终止,不允许再有事件发出。
在一个正确运行的事件序列中, onCompleted() 和 onError() 有且只有一个,并且是事件序列中的最后一个。需要注意的是,onCompleted() 和 onError() 二者也是互斥的,即在队列中调用了其中一个,就不应该再调用另一个。
一般不会直接使用Observer接口,而是使用实现了其接口的抽象类Subscriber,Observer用法如下:
public void testObserver(View view) { Observable.just(12) .subscribe(new Observer<Integer>() { @Override public void onCompleted() { Log.e(TAG, "" + "onCompleted"); } @Override public void onError(Throwable e) { e.printStackTrace(); } @Override public void onNext(Integer integer) { Log.e(TAG, "" + integer); } });}
5 Subscriber
Subscriber 是一个实现了 Observer 和 Subscription 两个接口的抽象类。 Subscriber 对 Observer 接口进行了一些扩展,但他们的基本使用方式是完全一样的:
Subscriber与Observer相比
- Subscriber多了一个onStart方法
- Subscriber多了一个unsubscribe()方法,用于取消订阅
- Subscriber多了一个isUnsubscribed()方法,用于判断订阅状态
6 Subject
Subject 是一个神奇的对象,它可以是一个Observable同时也可以是一个Observer。Subject是一个抽象类,继承了Observable的同时也实现了Observer接口。
常用的Subject实现类有以下几个:
6.1 PublishSubject
PublishSubject只会把在订阅发生的时间点之后来自原始Observable的数据发射给观察者。需要注意的是,PublishSubject可能会一创建完成就立刻开始发射数据(除非你可以阻止它发生),因此这里有一个风险:在PublishSubject被创建后到有观察者订阅它之前这个时间段内,一个或多个数据可能会丢失。
public void publishSubject(View view) { //create方法是无参的,需要通过后续的onNext,onComplete,onError等方法发送数据 PublishSubject<String> subject = PublishSubject.create(); subject.onNext("1. Hello World"); subject.subscribe(new Subscriber<String>() { @Override public void onCompleted() { Log.e("PublishSubject", "onCompleted"); } @Override public void onError(Throwable e) { Log.e("PublishSubject", "onError " + e.getMessage()); } @Override public void onNext(String s) { Log.e("PublishSubject", "onNext " + s); } }); subject.onNext("2.This is Felix"); subject.onCompleted();}
以上demo打印结果如下,只有订阅以后的消息推送才会接收到,这里需要注意订阅之前的subject.onCompleted/subject.onError回调,也会在订阅之后收到,标志此Observable结束:
com.felix.testrxjava E/PublishSubject: onNext 2.This is Felixcom.felix.testrxjava E/PublishSubject: onCompleted
PublishSubject一般用于创建连接Observables并且同时可被观测的实体。比如为公共资源创建独立、抽象或更易观测的点这种场景。例如如下场景,我们需要监测一个内部请求的结果,不管成功失败。
//创建一个PublishSubject用于接收最终的结果final PublishSubject<Boolean> publishSubject = PublishSubject.create();publishSubject.subscribe(new Action1<Boolean>() { @Override public void call(Boolean aBoolean) { //最终的结果在这里接收监听并处理 Log.e("PublishSubject", "subscribe-- " + aBoolean); }}); //创建一个私有的Observable,只有内部的变量才能访问到Observable.create(new Observable.OnSubscribe<Integer>() { @Override public void call(Subscriber<? super Integer> subscriber) { for (int i = 0; i < 10; i++) { subscriber.onNext(i); } subscriber.onCompleted(); }}).doOnCompleted(new Action0() { ////当Observable结束时要会调用这里 @Override public void call() { publishSubject.onNext(true); }}).subscribe();//空的订阅表示不关注中间过程
以上运行的结果,就达到了只监控最终结果的目的。
com.felix.testrxjava E/PublishSubject: subscribe-- true
6.2 BehaviorSubject
当观察者订阅BehaviorSubject时,它开始发射原始Observable最近发射的数据(如果此时还没有收到任何数据,它会发射一个默认值),然后继续发射订阅后的数据流。
public void behaviorSubject(View view) { Integer integer = 12; BehaviorSubject<Integer> behaviorSubject =BehaviorSubject.create(integer); behaviorSubject.subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("BehaviorSubject1", "1. " + integer); } }); behaviorSubject.onNext(11); behaviorSubject.onNext(23); behaviorSubject.onNext(58); behaviorSubject.subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("BehaviorSubject2", "2. " + integer); } });}
以上例子,BehaviorSubject.create()
,不传参数的时候,是不会发送默认值的。输出如下:
com.felix.testrxjava E/BehaviorSubject1: 1. 11com.felix.testrxjava E/BehaviorSubject1: 1. 23com.felix.testrxjava E/BehaviorSubject1: 1. 58com.felix.testrxjava E/BehaviorSubject2: 2. 58
带一个参数的时候,其内部会默认认为此参数是默认值的,也就会发送默认值即使这个参数为null。我们看看源码
//无参方法,默认第一个参数是null,第二个参数是false public static <T> BehaviorSubject<T> create() { return create(null, false);}//带有默认值的方法,默认第二个参数是truepublic static <T> BehaviorSubject<T> create(T defaultValue) { return create(defaultValue, true);}private static <T> BehaviorSubject<T> create(T defaultValue, boolean hasDefault) { final SubjectSubscriptionManager<T> state = new SubjectSubscriptionManager<T>(); if (hasDefault){ state.setLatest(NotificationLite.instance().next(defaultValue)); } state.onAdded = new Action1<SubjectObserver<T>>() { @Override public void call(SubjectObserver<T> o) { o.emitFirst(state.getLatest(), state.nl); } }; state.onTerminated = state.onAdded; return new BehaviorSubject<T>(state, state); }
6.3 ReplaySubject
ReplaySubject会缓存它所订阅的所有数据,向任意一个订阅它的观察者重发。
public void replaySubject(View view) { ReplaySubject<Integer> subject = ReplaySubject.create(); for (int i = 0; i < 3; i++) { subject.onNext(i); } subject.subscribe(new Subscriber<Integer>() { @Override public void onCompleted() { Log.e("replaySubject", "onCompleted"); } @Override public void onError(Throwable e) { Log.e("replaySubject", "onError " + e.getMessage()); } @Override public void onNext(Integer integer) { Log.e("replaySubject", "onError " + integer); } }); for (int i = 0; i < 5; i++) { subject.onNext(i); } subject.subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("replaySubject2", "onError2 " + integer); } });}
以上执行的结果将都打印出所有循环的数据,由于没有执行取消订阅unsubscribe方法。
com.felix.testrxjava E/replaySubject: onError 0com.felix.testrxjava E/replaySubject: onError 1com.felix.testrxjava E/replaySubject: onError 2com.felix.testrxjava E/replaySubject: onError 0com.felix.testrxjava E/replaySubject: onError 1com.felix.testrxjava E/replaySubject: onError 2com.felix.testrxjava E/replaySubject: onError 3com.felix.testrxjava E/replaySubject: onError 4com.felix.testrxjava E/replaySubject: onError2 0com.felix.testrxjava E/replaySubject: onError2 1com.felix.testrxjava E/replaySubject: onError2 2com.felix.testrxjava E/replaySubject: onError2 0com.felix.testrxjava E/replaySubject: onError2 1com.felix.testrxjava E/replaySubject: onError2 2com.felix.testrxjava E/replaySubject: onError2 3com.felix.testrxjava E/replaySubject: onError2 4
如果你把ReplaySubject当作一个观察者使用,注意不要从多个线程中调用它的onNext方法(包括其它的on系列方法),这可能导致同时(非顺序)调用,这会违反Observable协议,给Subject的结果增加了不确定性。
6.4 AsyncSubject
一个AsyncSubject只在原始Observable完成后,发射来自原始Observable的最后一个值。(如果原始Observable没有发射任何值,AsyncObject也不发射任何值)它会把这最后一个值发射给任何后续的观察者。
public void asyncSubject(View view) { AsyncSubject<Integer> subject = AsyncSubject.create(); subject.subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("asyncSubject", "1. " + integer); } }); for (int i = 0; i < 3; i++) { subject.onNext(i); } //onCompleted方法调用后才会触发订阅的回调,否则无回调。 subject.onCompleted(); subject.subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("asyncSubject2", "2. " + integer); } });}
输出结果如下
com.felix.testrxjava E/asyncSubject: 1. 2com.felix.testrxjava E/asyncSubject2: 2. 2
说明
- onCompleted方法调用后才会触发订阅的回调,否则无回调。
- 无论何时订阅,都会回调,而且都只会回调最终结果。
6.5 SerializedSubject
多个线程中调用Subject的onNext方法(包括其它的on系列方法),可能导致同时(非顺序)调用Subscriber,这会违反Observable协议,给Subject的结果增加了不确定性。 要避免此类问题,你可以将 Subject 转换为一个 SerializedSubject。SerializedSubject保证了同一时刻只有一个线程可以调用其方法发射数据。
我们看看传统的方式
public void serializedSubject(View view) { final PublishSubject<String> subject = PublishSubject.create(); subject.subscribe(new Action1<String>() { @Override public void call(String s) { Log.e("serializedSubject", s); pos++; } }); ExecutorService service = Executors.newFixedThreadPool(3); for (int i = 0; i < 3; i++) { service.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 3; j++) { SystemClock.sleep(300); subject.onNext(Thread.currentThread().getName() + " " + pos); } } }); } service.shutdown();}
输出结果如下,我们看到,线程1和线程2同时访问了onNext方法,这里就导致了输出两个一样的结果 3
serializedSubject: pool-1-thread-1 0serializedSubject: pool-1-thread-2 1serializedSubject: pool-1-thread-3 2serializedSubject: pool-1-thread-1 3serializedSubject: pool-1-thread-2 3serializedSubject: pool-1-thread-3 5serializedSubject: pool-1-thread-1 6serializedSubject: pool-1-thread-2 7serializedSubject: pool-1-thread-3 8
如果我们加上serializedSubject装饰一下
public void serializedSubject(View view) { final PublishSubject<String> subject = PublishSubject.create(); final SerializedSubject serializedSubject = new SerializedSubject(subject); serializedSubject.subscribe(new Action1<String>() { @Override public void call(String s) { Log.e("serializedSubject", s); pos++; } }); ExecutorService service = Executors.newFixedThreadPool(3); for (int i = 0; i < 3; i++) { service.submit(new Runnable() { @Override public void run() { for (int j = 0; j < 3; j++) { SystemClock.sleep(300); serializedSubject.onNext(Thread.currentThread().getName() + " " + pos); } } }); } service.shutdown();}
我们再看看输出,如下:无论重试多少次,都会发现不会重复了。加了SerializedSubject的装饰,就不会同时又多个线程访问onNext方法了。
serializedSubject: pool-1-thread-1 0serializedSubject: pool-1-thread-2 1serializedSubject: pool-1-thread-3 2serializedSubject: pool-1-thread-1 3serializedSubject: pool-1-thread-2 4serializedSubject: pool-1-thread-3 5serializedSubject: pool-1-thread-1 6serializedSubject: pool-1-thread-2 7serializedSubject: pool-1-thread-3 8
这里还需要注意,SerializedSubject用来包装其他Subject才有这种效果,直接调用create/just等方法的话,将会吧SerializedSubject转化为Observable。
6.6 Subject总结
- Subject没法指定异步线程,更像是EventBus通过订阅来实现事件通知。
- just(T)、from(T)、create(T)会把Subject转换为Obserable
- Subject.asObservable也会返回一个Obserable
7 Scheduler
如果你想给Observable操作符链添加多线程功能,你可以指定操作符(或者特定的Observable)在特定的调度器(Scheduler)上执行。
RxJava中常见的调度器:
不要用于IO操作(IO操作请使用Schedulers.io())
默认线程数等于处理器的数量 Schedulers.from(executor) 使用指定的Executor作为调度器 Schedulers.immediate( ) 在当前线程立即开始执行任 Schedulers.io( ) 用于IO密集型任务,如异步阻塞IO操作,
这个调度器的线程池会根据需要增长;
对于普通的计算任务,请使用Schedulers.computation();
Schedulers.io( )默认是一个CachedThreadScheduler,
很像一个有线程缓存的新线程调度器 Schedulers.newThread( ) 为每个任务创建一个新线程 Schedulers.trampoline( ) 当其它排队的任务完成后,在当前线程排队开始执行
使用ObserveOn和SubscribeOn操作符,你可以让Observable在一个特定的调度器上执行,ObserveOn指示一个Observable在一个特定的调度器上调用观察者的onNext, onError和onCompleted方法,SubscribeOn更进一步,它指示Observable将全部的处理过程(包括发射数据和通知)放在特定的调度器上执行。
7.1 subscribeOn
subscribeOn改变了Observable本身产生事件的schedule以及发出事件后相关处理事件的程序所在的schedule,subscribeOn()主要改变的是订阅的线程,即call()执行的线程.
subscribeOn则是一次性的,无论在什么地方调用,总是从改变最原始的Observable开始影响整个Observable的处理。
public void subscribeOn(View view) { Observable.create(subscriber -> { Log.e("call", "call " + Thread.currentThread().getId()); if (new Random().nextBoolean()) { subscriber.onNext("hello"); subscriber.onCompleted(); } else { subscriber.onError(new Exception("error")); } }).cast(String.class) .subscribeOn(Schedulers.newThread()) .subscribe(new Subscriber<String>() { @Override public void onStart() { Log.e("onStart", "onStart " + Thread.currentThread().getId()); } @Override public void onCompleted() { Log.e("onCompleted", "onCompleted " + Thread.currentThread().getId()); } @Override public void onError(Throwable e) { Log.e("onError", "onError " + Thread.currentThread().getId()); } @Override public void onNext(String s) { Log.e("onNext", "onNext " + Thread.currentThread().getId()); } });}
看看返回值,切换了call的线程以后,onNext/onCompleted/onError执行的线程都跟着变成了切换后的线程。可以将切换的线程注释掉,会发现所有的线程都变成了1,也就是默认都在当前线程运行。这里需要注意:onStart方法默认在Observable执行的线程运行(当前1为主线程)
02-15 18:49:33.903 10731-10731/com.felix.testrxjava E/onStart: onStart 102-15 18:49:33.907 10731-11732/com.felix.testrxjava E/call: call 93602-15 18:49:33.907 10731-11732/com.felix.testrxjava E/onNext: onNext 93602-15 18:49:33.907 10731-11732/com.felix.testrxjava E/onCompleted: onCompleted 936//点击了两次,随机函数产生了两种结果02-15 18:49:52.701 10731-10731/com.felix.testrxjava E/onStart: onStart 102-15 18:49:52.702 10731-12100/com.felix.testrxjava E/call: call 93702-15 18:49:52.702 10731-12100/com.felix.testrxjava E/onError: onError 937
7.2 ObserveOn
ObserveOn 改变了对发出事件后相关处理事件的程序所在的schedule。observeOn()主要改变的是发送的线程,即onNext, onCompleted, onError方法执行的线程。
ObserveOn可以多次调用,多次改变不同的接受者所在的schedule,对调用这个函数之后的Observable造成影响。
注意:当遇到一个异常时ObserveOn会立即向前传递这个onError终止通知,它不会等待慢速消费的Observable接受任何之前它已经收到但还没有发射的数据项。这可能意味着onError通知会跳到(并吞掉)原始Observable发射的数据项前面。
7.3 unsubscribeOn
有些 Observable 会依赖一些资源,当该 Observable 完成后释放这些资源。如果释放资源比较耗时的话,可以通过 unsubscribeOn 来指定 释放资源代码执行的线程。
7.4 Scheduler.Worker
7.5
8 操作符之过滤操作
8.1 Filter/ofType
过滤,过滤掉没有通过谓词测试的数据项,只发射通过测试的
java
public void filter(View v) {
Observable.just(12, 3, 4, 5, 7, 9, 8)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer < 6;
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
Log.e("filter", integer + "");
}
});
}
ofType是filter操作符的一个特殊形式。它过滤一个Observable只返回指定类型的数据。
ofType默认不在任何特定的调度器上指定。
8.2 take/takeLast/takeLastBuffer
只保留前面/后面几条数据。
值得注意的是因为takeLast()方法只能作用于一组有限的序列(发射元素),它只能应用于一个完整的序列。
public void takeLast(View view) { Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) .take(7).takeLast(4).subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("take", integer + ""); } });}
takeLastBuffer,它和takeLast类似,,唯一的不同是它把所有的数据项收集到一个List再发射,而不是依次发射一个。
8.3 distinct/distinctUntilChanged
distinct()作用于一个完整的序列,然后得到重复的过滤项,它需要记录每一个发射的值。如果你在处理一大堆序列或者大的数据记得关注内存使用情况。
distinctUntilChanged 在一个可观测序列发射一个不同于之前值的一个新值。
public void distinct(View view){ Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) .take(3).repeat(4).distinct().subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("distinct", integer + ""); } });}public void distinctUntilsChanged(View view){ Observable.just(2,2,3,2,4,5,6,5,3,3).distinctUntilChanged() .subscribe(new Action1<Integer>() { @Override public void call(Integer integer) { Log.e("distinctUntilsChanged", integer + ""); } });}
8.4 first/last/elementAt
first 只发送第一个数据
firstOrDefault 只发射第一项数据,如果Observable为空就发射默认值
last 只发送最后一个数据
lastOrDefault 只发射最后一项数据,如果Observable为空就发射默认值
elementAt(N) 只发送第N个数据
elementAtOrDefault(N) 只发送第N个数据,如果Observable为空或者不存在第N个数据就发射默认值
8.5 sample/throttleLast
定期发射Observable最近的数据
8.6 throttleFirst
定期发射Observable发射的第一项数据
8.7 timeout
使用timeout()函数来监听源可观测序列,就是在我们设定的时间间隔内如果没有得到一个值则发射一个错误。我们可以认为timeout()为一个Observable的限时的副本。如果在指定的时间间隔内Observable不发射值的话,它监听的原始的Observable时就会触发onError()函数
8.8 debounce/throttleWithTimeout
过滤掉由Observable发射的速率过快的数据;如果在一个指定的时间间隔过去了仍旧没有发射一个,那么它将发射最后的那个。
debounce()函数开启一个内部定时器,如果在这个时间间隔内没有新的数据发射,则新的Observable发射出最后一个数据:
8.9 ignoreElements
丢弃所有的正常数据,只发射错误或完成通知
8.10 skip/SkipLast
使用Skip操作符,你可以忽略Observable’发射的前N项数据,只保留之后的数据。
使用SkipLast操作符修改原始Observable,你可以忽略Observable’发射的后N项数据,只保留前面的数据。
skip/skipLast的这个变体默认在computation调度器上执行,但是你可以使用第三个参数指定其它的调度器。
9 变换
RxJava提供了几个mapping函数:map(),flatMap(),concatMap(),flatMapIterable()以及switchMap().所有这些函数都作用于一个可观测序列,然后变换它发射的值,最后用一种新的形式返回它们。
9.1 map
对序列的每一项都应用一个函数来变换Observable发射的数据序列
9.2 flatMap/concatMap/flatMapIterable
将Observable发射的数据集合变换为Observables集合,然后将这些Observable发射的数据平坦化的放进一个单独的Observable
任何一个Observables发生错误的情况,flatMap/concatMap/flatMapIterable将会触发它自己的onError()函数并放弃整个链。
三者的区别是:
- flatMap可以交叉,也就是不能够保证在最终生成的Observable中源Observables确切的发射顺序
- concatMap提供了一种能够把发射的值连续在一起的铺平函数,而不是合并它们。
- flatMapInterable()和flatMap()很像。仅有的本质不同是它将源数据两两结成对并生成Iterable,而不是原始数据项和生成的Observables。
flatMap的例子:
public void flatMap(View view) { Observable.just(0, 1).flatMap(new Func1<Integer, Observable<String>>() { @Override public Observable<String> call(final Integer i) { if (i % 2 == 0) { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { for (int j = 0; j < 3; j++) { SystemClock.sleep(500); subscriber.onNext(Thread.currentThread().getName() + "--" + i + "--" + j); } subscriber.onCompleted(); } //subscribeOn改变了call执行所在的线程 }).subscribeOn(Schedulers.newThread()); } else { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { for (int j = 0; j < 3; j++) { SystemClock.sleep(500); subscriber.onNext(Thread.currentThread().getName() + "++" + i + "++" + j); } subscriber.onCompleted(); } }).subscribeOn(Schedulers.newThread()); } } }).subscribe(new Action1<String>() { @Override public void call(String s) { Log.e("flatMap", s); } });}
其输出结果如下所示,我们看到两次的数据是一个合并操作,是无序的:
01-31 19:40:06.136 4542-4987/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-1--0--001-31 19:40:06.136 4542-4988/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-2++1++001-31 19:40:06.636 4542-4987/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-1--0--101-31 19:40:06.636 4542-4988/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-2++1++101-31 19:40:07.136 4542-4987/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-1--0--201-31 19:40:07.137 4542-4988/com.felix.testrxjava E/flatMap: RxNewThreadScheduler-2++1++2
我们再看看concatMap
public void concatMap(View view) { Observable.just(0, 1).concatMap(new Func1<Integer, Observable<String>>() { @Override public Observable<String> call(final Integer i) { if (i % 2 == 0) { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { for (int j = 0; j < 3; j++) { SystemClock.sleep(500); subscriber.onNext(Thread.currentThread().getName() + "--" + i + "--" + j); } subscriber.onCompleted(); } //subscribeOn改变了call执行所在的线程 }).subscribeOn(Schedulers.newThread()); } else { return Observable.create(new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { for (int j = 0; j < 3; j++) { SystemClock.sleep(500); subscriber.onNext(Thread.currentThread().getName() + "++" + i + "++" + j); } subscriber.onCompleted(); } }).subscribeOn(Schedulers.newThread()); } } }).subscribe(new Action1<String>() { @Override public void call(String s) { Log.e("concatMap", s); } });}
输出结果如下,我们可以看到这是一个串行的合并操作,且需要注意的是,第一个Observable的subscriber.onCompleted方法调用结束以后才会开始第二个,若第一个未调用subscriber.onCompleted,则永远不会调用第二个的onNext方法,而是一直等待
01-31 19:44:52.709 9098-9382/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-3--0--001-31 19:44:53.211 9098-9382/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-3--0--101-31 19:44:53.711 9098-9382/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-3--0--201-31 19:44:54.216 9098-9407/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-4++1++001-31 19:44:54.717 9098-9407/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-4++1++101-31 19:44:55.217 9098-9407/com.felix.testrxjava E/concatMap: RxNewThreadScheduler-4++1++2
9.3 switchMap
和flatMap()很像,除了一点:每当源Observable发射一个新的数据项(Observable)时,它将取消订阅并停止监视之前那个数据项产生的Observable,并开始监视当前发射的这一个.
我们看一下这个例子,
java
public void switchMap(View v) {
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> subscriber) {
subscriber.onNext(0);
SystemClock.sleep(800);
subscriber.onNext(1);
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.newThread())
.switchMap(new Func1<Integer, Observable<String>>() {
@Override
public Observable<String> call(final Integer i) {
if (i % 2 == 0) {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
for (int j = 0; j < 3; j++) {
SystemClock.sleep(500);
subscriber.onNext(Thread.currentThread().getName() + "--" + i + "--" + j);
}
subscriber.onCompleted();
}
//subscribeOn改变了call执行所在的线程
}).subscribeOn(Schedulers.newThread());
} else {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
for (int j = 0; j < 3; j++) {
SystemClock.sleep(500);
subscriber.onNext(Thread.currentThread().getName() + "++" + i + "++" + j);
}
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.newThread());
}
}
}).subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.e("switchMap", s);
}
});
}
其输出结果如下,我们可以看出来,当第二个订阅发出来以后,第一个订阅就结束了,不会再次调用。
java
01-31 19:52:57.919 15284-15545/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-5--0--0
01-31 19:52:58.720 15284-15562/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-6++1++0
01-31 19:52:59.220 15284-15562/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-6++1++1
01-31 19:52:59.720 15284-15562/com.felix.testrxjava E/switchMap: RxNewThreadScheduler-6++1++2
9.4 scan
scan()函数对原始Observable发射的每一项数据都应用一个函数,计算出函数的结果值,并将该值填充回可观测序列,等待和下一次发射的数据一起使用。
public void scan(View view) { Observable.range(1, 10) .scan((sum, value) -> sum + value) .subscribe(sum -> Log.e("scan", sum + ""));}
输出结果如下,这是一个求和操作,计算1到10的和:
01-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 101-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 301-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 601-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 1001-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 1501-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 2101-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 2801-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 3601-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 4501-31 20:39:35.589 3491-3491/com.felix.testrxjava E/scan: 55
9.5 groupBy
GroupBy操作符将原始Observable分拆为一些Observables集合,它们中的每一个发射原始Observable数据序列的一个子序列。哪个数据项由哪一个Observable发射是由一个函数判定的,这个函数给每一项指定一个Key,Key相同的数据会被同一个Observable发射。
groupBy将原始Observable分解为一个发射多个GroupedObservable的Observable,一旦有订阅,每个GroupedObservable就开始缓存数据。因此,如果你忽略这些GroupedObservable中的任何一个,这个缓存可能形成一个潜在的内存泄露。因此,如果你不想观察,也不要忽略GroupedObservable。你应该使用像take(0)这样会丢弃自己的缓存的操作符。
如果你取消订阅一个GroupedObservable,那个Observable将会终止。如果之后原始的Observable又发射了一个与这个Observable的Key匹配的数据,groupBy将会为这个Key创建一个新的GroupedObservable。
看一个例子,将数组1-5 按 x % 2 来分组。
public void groupBy(View view) { Observable.range(1, 5).groupBy(a -> a % 2) .subscribe(new Observer<GroupedObservable<Integer, Integer>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(GroupedObservable<Integer, Integer> integerIntegerGroupedObservable) { integerIntegerGroupedObservable.subscribe((value -> Log.e("groupBy", "group:" + integerIntegerGroupedObservable.getKey() + " Value:" + value))); } });}
我们可以看到,groupBy的返回值其实是一嵌套了GroupedObservable的Observable,即Observable<GroupedObservable<K, T>>
,所以这里看到的是两层的订阅,外层订阅获取分组,内层订阅分组内的GroupedObservable。其中GroupedObservable.getKey()
用来获取分组ID。输出结果如下:
02-01 22:35:11.274 3105-3105/com.felix.testrxjava E/groupBy: group:1 Value:102-01 22:35:11.274 3105-3105/com.felix.testrxjava E/groupBy: group:0 Value:202-01 22:35:11.274 3105-3105/com.felix.testrxjava E/groupBy: group:1 Value:302-01 22:35:11.275 3105-3105/com.felix.testrxjava E/groupBy: group:0 Value:402-01 22:35:11.275 3105-3105/com.felix.testrxjava E/groupBy: group:1 Value:5
9.6 buffer
buffer(count)以列表(List)的形式发射非重叠的缓存,每一个缓存至多包含来自原始Observable的count项数据(最后发射的列表数据可能少于count项)
Observable.range(1, 10).buffer(3) .subscribe(x -> Log.e("buffer(count)", x + ""));
看看其输出:
02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [1, 2, 3]02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [4, 5, 6]02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [7, 8, 9]02-01 23:49:29.908 21934-21934/com.felix.testrxjava E/buffer(count): [10]
buffer(count, skip)从原始Observable的第一项数据开始创建新的缓存,此后每当收到skip项数据,用count项数据填充缓存:开头的一项和后续的count-1项,它以列表(List)的形式发射缓存,取决于count和skip的值,这些缓存可能会有重叠部分(比如skip < count时),也可能会有间隙(比如skip > count时)。
Observable.range(1, 10).buffer(3, 5) .subscribe(x -> Log.e("buffer(count, skip>)", x + ""));Observable.range(1, 5).buffer(3, 2) .subscribe(x -> Log.e("buffer(count, skip<)", x + ""));
看看其输出,skip大的时候,有间隙,skip小的时候有重叠:
02-02 00:09:08.467 8665-8665/com.felix.testrxjava E/buffer(count, skip>): [1, 2, 3]02-02 00:09:08.467 8665-8665/com.felix.testrxjava E/buffer(count, skip>): [6, 7, 8]02-02 00:09:08.468 8665-8665/com.felix.testrxjava E/buffer(count, skip<): [1, 2, 3]02-02 00:09:08.468 8665-8665/com.felix.testrxjava E/buffer(count, skip<): [3, 4, 5]02-02 00:09:08.468 8665-8665/com.felix.testrxjava E/buffer(count, skip<): [5]
buffer(Func0()) 当它订阅原来的Observable时,buffer(bufferClosingSelector)开始将数据收集到一个List,然后它调用bufferClosingSelector生成第二个Observable,当第二个Observable发射一个TClosing时,buffer发射当前的List,然后重复这个过程:开始组装一个新的List,然后调用bufferClosingSelector创建一个新的Observable并监视它。它会一直这样做直到原来的Observable执行完成.
buffer(boundary)监视一个名叫boundary的Observable,每当这个Observable发射了一个值,它就创建一个新的List开始收集来自原始Observable的数据并发射原来的List
buffer(bufferOpenings, bufferClosingSelector)监视这个叫bufferOpenings的Observable(它发射BufferOpening对象),每当bufferOpenings发射了一个数据时,它就创建一个新的List开始收集原始Observable的数据,并将bufferOpenings传递给closingSelector函数。这个函数返回一个Observable。buffer监视这个Observable,当它检测到一个来自这个Observable的数据时,就关闭List并且发射它自己的数据(之前的那个List)
buffer(timespan, unit)定期以List的形式发射新的数据,每个时间段,收集来自原始Observable的数据(从前面一个数据包裹之后,或者如果是第一个数据包裹,从有观察者订阅原来的Observale之后开始)。还有另一个版本的buffer接受一个Scheduler参数,默认情况下会使用computation调度器。
“`java
Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber
7. 每当收到来自原始Observable的count项数据,或者每过了一段指定的时间后,buffer(timespan, unit, count)就以List的形式发射这期间的数据,即使数据项少于count项。还有另一个版本的buffer接受一个Scheduler参数,默认情况下会使用computation调度器。8. buffer(timespan, timeshift, unit)在每一个timeshift时期内都创建一个新的List,然后用原始Observable发射的每一项数据填充这个列表(在把这个List当做自己的数据发射前,从创建时开始,直到过了timespan这么长的时间)。如果timespan长于timeshift,它发射的数据包将会重叠,因此可能包含重复的数据项。**注意:如果原来的Observable发射了一个onError通知,Buffer会立即传递这个通知,而不是首先发射缓存的数据,即使在这之前缓存中包含了原始Observable发射的数据**###9.7 windowRxJava的window()函数和buffer()很像,但是它发射的是Observable而不是列表。```javaObservable.range(1, 10).window(3) .subscribe(integerObservable -> integerObservable.subscribe(c -> Log.e("window(count)", "" + c)));Observable.range(1, 10).window(3, 5) .subscribe(integerObservable -> integerObservable.subscribe(c -> Log.e("window(count,skip>)", "" + c)));Observable.range(1, 10).window(3, 2) .subscribe(integerObservable -> integerObservable.subscribe(c -> Log.e("window(count,skip<)", "" + c)));<div class="se-preview-section-delimiter"></div>
9.8 cast
cast()函数是map()操作符的特殊版本。它将源Observable中的每一项数据都转换为新的类型,把它变成了不同的Class。
这个类一般用于lamda表达式中的泛型被擦除后,用于将Object类型的返回值转换为真正的返回值类型。后续会有很多例子用到,这里就不举例说明了。
10 组合
10.1 merge
把两个甚至更多的Observables合并到他们发射的数据项里。使用Observable.merge(),我们可以创建新的Observable—- MergedObservable,它在单个可观测序列中发射源Observables发出的所有数据。
public void merge(View view) { Observable.merge(Observable.create(subscriber -> { for (int i = 0; i < 3; i++) { subscriber.onNext(i); SystemClock.sleep(300); } subscriber.onCompleted(); }).subscribeOn(Schedulers.newThread()), Observable.create(subscriber -> { for (int i = 6; i < 8; i++) { subscriber.onNext(i); SystemClock.sleep(200); } subscriber.onError(new Exception("error")); }).subscribeOn(Schedulers.newThread())) .subscribe(x -> Log.e("merge", x + ""), e -> e.printStackTrace());}<div class="se-preview-section-delimiter"></div>
我们看看输出结果
02-03 09:19:24.415 30965-31375/com.felix.testrxjava E/merge: 002-03 09:19:24.415 30965-31376/com.felix.testrxjava E/merge: 602-03 09:19:24.615 30965-31376/com.felix.testrxjava E/merge: 702-03 09:19:24.715 30965-31375/com.felix.testrxjava E/merge: 102-03 09:19:24.816 30965-31376/com.felix.testrxjava W/System.err: java.lang.Exception: error<div class="se-preview-section-delimiter"></div>
每个Observable抛出的错误都将会打断合并。如果你需要避免这种情况,RxJava提供了mergeDelayError(),它能从一个Observable中继续发射数据即便是其中有一个抛出了错误。当所有的Observables都完成时,mergeDelayError()将会发射onError()
merge可能会让合并的Observables发射的数据交错而concat不会让数据交错,它会按顺序一个接着一个发射多个Observables的发射物
merge是静态方法,mergeWith是对象方法。 举个例子,Observable.merge(odds,evens)等价于odds.mergeWith(evens)
10.2 zip
zip()合并两个或者多个Observables发射出的数据项,根据指定的函数Func*变换它们,并发射一个新值。
public void zip(View view) { Observable.zip(Observable.interval(1000, TimeUnit.MILLISECONDS) .map(key -> ((char) (97 + key)) + ""), interval(1500, TimeUnit.MILLISECONDS), (v1, v2) -> updateData(v1, v2)) .take(8) .subscribe(x -> Log.e("zip", x + ""));}private String updateData(String v1, Long v2) { return v1 + v2;}<div class="se-preview-section-delimiter"></div>
输出结果如下
02-05 09:25:14.240 12433-13512/com.felix.testrxjava E/zip: a002-05 09:25:15.740 12433-13512/com.felix.testrxjava E/zip: b102-05 09:25:17.240 12433-13512/com.felix.testrxjava E/zip: c202-05 09:25:18.739 12433-13512/com.felix.testrxjava E/zip: d302-05 09:25:20.240 12433-13512/com.felix.testrxjava E/zip: e402-05 09:25:21.740 12433-13512/com.felix.testrxjava E/zip: f502-05 09:25:23.240 12433-13512/com.felix.testrxjava E/zip: g602-05 09:25:24.741 12433-13512/com.felix.testrxjava E/zip: h7<div class="se-preview-section-delimiter"></div>
10.3 join
join()函数基于时间窗口将两个Observables发射的数据结合在一起。join有四个参数, 我们解释下join()需要的参数:
- 第二个Observable和源Observable结合。
- Func1参数:在指定的由时间窗口定义时间间隔内,源Observable发射的数据和从第二个Observable发射的数据相互配合返回的Observable。
- Func1参数:在指定的由时间窗口定义时间间隔内,第二个Observable发射的数据和从源Observable发射的数据相互配合返回的Observable。
- Func2参数:定义已发射的数据如何与新发射的数据项相结合。
说的简单点就是:join的效果类似于排列组合,把第一个数据源A作为基座窗口,他根据自己的节奏(参数1 Func1)不断发射数据元素,第二个数据源B,也按自己的节奏(参数2 Func1),它每发射一个数据,我们都把它和第一个数据源A中已经发射的数据进行一对一匹配(Func2);
举例来说,如果某一时刻B发射了一个数据 0 ,此时A已经发射了 a,b 共两个数据,那么我们的合并操作就会把1依次与a,b配对,得到数据:a0; b0;
如下
public void join(View view) { Observable<String> observable1 = Observable.interval(1, TimeUnit.SECONDS) .map(key -> ((char) (97 + key)) + ""); Observable<Long> observable2 = Observable.interval(1, TimeUnit.SECONDS); observable1.join(observable2, str1 -> Observable.timer(2, TimeUnit.SECONDS), str2 -> Observable.timer(1, TimeUnit.SECONDS), this::updateData).observeOn(AndroidSchedulers.mainThread()) .take(5).subscribe(s -> Log.e("join", s));}<div class="se-preview-section-delimiter"></div>
输出结果如下:
02-04 23:01:29.666 6763-6763/com.felix.testrxjava E/join: a002-04 23:01:30.664 6763-6763/com.felix.testrxjava E/join: b002-04 23:01:30.665 6763-6763/com.felix.testrxjava E/join: b102-04 23:01:30.665 6763-6763/com.felix.testrxjava E/join: a102-04 23:01:31.664 6763-6763/com.felix.testrxjava E/join: c1<div class="se-preview-section-delimiter"></div>
10.4 combineLatest
RxJava的combineLatest()函数有点像zip()函数的特殊形式。正如我们已经学习的,zip()作用于最近未打包的两个Observables。相反,combineLatest()作用于最近发射的数据项:如果Observable1发射了A并且Observable2发射了B和C,combineLatest()将会分组处理AB和AC
我们和zip对比一下
public void combineLatest(View view) { Observable.combineLatest(Observable.interval(1000, TimeUnit.MILLISECONDS) .map(key -> ((char) (97 + key)) + ""), interval(1500, TimeUnit.MILLISECONDS), (v1, v2) -> updateData(v1, v2)) .take(8) .subscribe(x -> Log.e("combineLatest", x + ""));}<div class="se-preview-section-delimiter"></div>
输出结果为:
02-05 09:26:01.268 12433-14209/com.felix.testrxjava E/combineLatest: a002-05 09:26:01.767 12433-14208/com.felix.testrxjava E/combineLatest: b002-05 09:26:02.769 12433-14209/com.felix.testrxjava E/combineLatest: b102-05 09:26:02.769 12433-14209/com.felix.testrxjava E/combineLatest: c102-05 09:26:03.767 12433-14208/com.felix.testrxjava E/combineLatest: d102-05 09:26:04.268 12433-14209/com.felix.testrxjava E/combineLatest: d202-05 09:26:04.768 12433-14208/com.felix.testrxjava E/combineLatest: e202-05 09:26:05.768 12433-14209/com.felix.testrxjava E/combineLatest: e3<div class="se-preview-section-delimiter"></div>
可以看出来,zip是木有重复的,而combineLatest合并是有重复的。这就是区别,前者是取的未打包的数据,后者是取的最近发射的数据(不管是否未打包)
10.5 switchOnNext
将一个发射多个Observables的Observable转换成另一个单独的Observable,后者发射那些Observables最近发射的数据项
switchOnNext订阅一个发射多个Observables的Observable。它每次观察那些Observables中的一个,Switch返回的这个Observable取消订阅前一个发射数据的Observable,开始发射最近的Observable发射的数据。注意:当原始Observable发射了一个新的Observable时(不是这个新的Observable发射了一条数据时),它将取消订阅之前的那个Observable。这意味着,在后来那个Observable产生之后到它开始发射数据之前的这段时间里,前一个Observable发射的数据将被丢弃。
public void switchOnNext(View view) { Observable.switchOnNext(Observable.create(subscriber -> { for (int i = 0; i < 3; i++) { //每2s调用一次创建一个新的Observable subscriber.onNext(createswitchOnNextObservable(i)); SystemClock.sleep(2000); } })).observeOn(AndroidSchedulers.mainThread()) .cast(String.class) .subscribe(x -> Log.e("switchOnNext", x));}private Observable<String> createswitchOnNextObservable(int index) { return Observable.create(subscriber -> { for (int i = 0; i < 4; i++) { //每个内部Observable 都是1s发射一次数据 subscriber.onNext("index " + index + " loop " + i); SystemClock.sleep(1000); } }).cast(String.class) .subscribeOn(Schedulers.newThread());}<div class="se-preview-section-delimiter"></div>
分析结果可以得出,第二个Observable开始发射数据的时候,第一个未接收的数据被遗弃了。
02-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 0 loop 002-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 0 loop 102-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 1 loop 002-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 1 loop 102-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 002-05 10:03:14.290 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 102-05 10:03:14.292 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 202-05 10:03:15.293 10116-10116/com.felix.testrxjava E/switchOnNext: index 2 loop 3<div class="se-preview-section-delimiter"></div>
10.6 StartWith
如果你想要一个Observable在发射数据之前先发射一个指定的数据序列,可以使用StartWith操作符。(如果你想一个Observable发射的数据末尾追加一个数据序列可以使用Concat操作符。)
public void startWith(View view) { Observable.just(5, 6, 7) .startWith(Observable.just(1, 2, 3)) .subscribe(x -> Log.e("startWith", x + ""));}<div class="se-preview-section-delimiter"></div>
输出如下,嵌套在前面
02-05 10:09:02.678 16388-16388/com.felix.testrxjava E/startWith: 102-05 10:09:02.678 16388-16388/com.felix.testrxjava E/startWith: 202-05 10:09:02.678 16388-16388/com.felix.testrxjava E/startWith: 302-05 10:09:02.679 16388-16388/com.felix.testrxjava E/startWith: 502-05 10:09:02.679 16388-16388/com.felix.testrxjava E/startWith: 602-05 10:09:02.679 16388-16388/com.felix.testrxjava E/startWith: 7<div class="se-preview-section-delimiter"></div>
10.7 And/Then/When
使用Pattern和Plan作为中介,将两个或多个Observable发射的数据集合并到一起.
And/Then/When操作符组合的行为类似于zip,但是它们使用一个中间数据结构。接受两个或多个Observable,一次一个将它们的发射物合并到Pattern对象,然后操作那个Pattern对象,变换为一个Plan。随后将这些Plan变换为Observable的发射物。详细见rxjava-joins模块。
11 错误处理
很多操作符可用于对Observable发射的onError通知做出响应或者从错误中恢复.
java的异常分为错误(error)和异常(exception)两种,它们都是继承于Throwable类。
错误(error)一般是比较严重的系统问题,比如我们经常遇到的OutOfMemoryError、StackOverflowError等都是错误。错误一般继承于Error类,而Error类又继承于Throwable类,如果需要捕获错误,需要使用try..catch(Error e)或者try..catch(Throwable e)句式。使用try..catch(Exception e)句式无法捕获错误
异常(Exception)也是继承于Throwable类,一般是根据实际处理业务抛出的异常,分为运行时异常(RuntimeException)和普通异常。普通异常直接继承于Exception类,如果方法内部没有通过try..catch句式进行处理,必须通过throws关键字把异常抛出外部进行处理(即checked异常);而运行时异常继承于RuntimeException类,如果方法内部没有通过try..catch句式进行处理,不需要显式通过throws关键字抛出外部,如IndexOutOfBoundsException、NullPointerException、ClassCastException等都是运行时异常,当然RuntimeException也是继承于Exception类,因此是可以通过try..catch(Exception e)句式进行捕获处理的。
11.1 onErrorResumeNext
onErrorReturn操作符是在Observable发生错误或异常的时候(即将回调oError方法时),拦截错误并执行指定的逻辑,返回一个跟源Observable相同类型的结果,最后回调订阅者的onComplete方法
public void onErrorResumeNext(View view) { Observable.error(new Exception("error")) .onErrorResumeNext(Observable.just("a", "b", "c")).cast(String.class) .subscribe(x -> Log.e("onErrorResumeNext(Obs)", x), error -> Log.e("onErrorResumeNext(Obs)", error.getMessage()), () -> Log.e("onErrorResumeNext(Obs)", "onCompleted")); Observable.error(new Exception("error")) .onErrorResumeNext(throwable -> { return Observable.just(throwable.getMessage(), "d", "e"); }).cast(String.class) .subscribe(x -> Log.e("onErrorResumeNext(Func)", x), error -> Log.e("onErrorResumeNext(Func)", error.getMessage()), () -> Log.e("onErrorResumeNext(Func)", "onCompleted"));}<div class="se-preview-section-delimiter"></div>
输出如下,我们可以发现,不仅调用了OnError,而且还调用了onCompleted,下同:
02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): a02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): b02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): c02-06 17:24:29.370 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Obs): onCompleted02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): error02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): d02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): e02-06 17:24:29.371 3541-3541/com.felix.testrxjava E/onErrorResumeNext(Func): onCompleted<div class="se-preview-section-delimiter"></div>
11.2 onErrorReturn
指示Observable在遇到错误时发射一个特定的数据,和onErrorResumeNext的区别是onErrorReturn的回调Func1返回的是一个值,而onErrorResumeNext返回的是一个Observable。
public void onErrorReturn(View view) { Observable.error(new Exception("error")) .onErrorReturn(throwable -> { return throwable.getMessage(); }).cast(String.class) .subscribe(x -> Log.e("onErrorReturn", x), error -> Log.e("onErrorReturn", error.getMessage()), () -> Log.e("onErrorReturn", "onCompleted"));}<div class="se-preview-section-delimiter"></div>
输出如下:
02-06 17:25:32.773 3541-3541/com.felix.testrxjava E/onErrorReturn: error02-06 17:25:32.773 3541-3541/com.felix.testrxjava E/onErrorReturn: onCompleted<div class="se-preview-section-delimiter"></div>
11.3 onExceptionResumeNext
指示Observable遇到错误时继续发射数据.
onExceptionResumeNext操作符和onErrorResumeNext操作符类似,不同的地方在于onErrorResumeNext操作符是当Observable发生错误或异常时触发,而onExceptionResumeNext是当Observable发生异常时才触发。
public void onExceptionResumeNext(View view) { Observable.create(subscriber -> { for (int i = 0; i < 10; i++) { if (i == 5) { subscriber.onError(new Exception("error")); } else { subscriber.onNext("is " + i); } } subscriber.onCompleted(); }).onErrorReturn(throwable -> throwable.getMessage()) .cast(String.class) .subscribe(x -> Log.e("onExceptionResumeNext", x), error -> Log.e("onExceptionResumeNext", error.getMessage()), () -> Log.e("onExceptionResumeNext", "onCompleted"));}<div class="se-preview-section-delimiter"></div>
输出结果:
02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 002-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 102-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 202-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 302-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: is 402-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: error02-07 06:27:55.285 6106-6106/com.felix.testrxjava E/onExceptionResumeNext: onCompleted<div class="se-preview-section-delimiter"></div>
11.4 retry
retry操作符是当Observable发生错误或者异常时,重新尝试执行Observable的逻辑,如果经过n次重新尝试执行后仍然出现错误或者异常,则最后回调执行onError方法;当然如果源Observable没有错误或者异常出现,则按照正常流程执行。
int index = 0;public void retry(View view) { Observable.create(subscriber -> { index++; subscriber.onNext("index "+index); subscriber.onError(new Exception("error index " + index)); }).retry().cast(String.class) .subscribe(x -> Log.e("retry", x), error -> Log.e("retry", error.getMessage()),<div class="se-preview-section-delimiter"></div>
默认的retry()会一直重试直到成功,也可以传一个整型值给retry来指定重试次数。
也可以传递一个Func2函数给retry,通过函数规则来判断是否需要重试。
11.5 retryWhen
retryWhen操作符类似于retry操作符,都是在源observable出现错误或者异常时,重新尝试执行源observable的逻辑,不同在于retryWhen操作符是在源Observable出现错误或者异常时,通过回调第二个Observable来判断是否重新尝试执行源Observable的逻辑,如果第二个Observable没有错误或者异常出现,则就会重新尝试执行源Observable的逻辑,否则就会直接回调执行订阅者的onError方法。
retryWhen的参数是一个Func1,通过Func1的返回的Observable来决定如何重试。如果这个Observable发射了一项数据,它就重新订阅,如果这个Observable发射的是onError通知,它就将这个通知传递给观察者然后终止。
摘录来自: mcxiaoke. “ReactiveX文档中文翻译”。 iBooks.
public void retryWhen(View view) { Observable.create(subscriber -> { index++; subscriber.onNext("index " + index); subscriber.onError(new Exception("error index " + index)); }).retryWhen(observable -> { return Observable.interval(3, TimeUnit.SECONDS); }).cast(String.class) .subscribe(x -> Log.e("retryWhen", x), error -> Log.e("retryWhen", error.getMessage()), () -> Log.e("retryWhen", "onCompleted"));}<div class="se-preview-section-delimiter"></div>
这个将按规则,没3s重试一次
02-08 11:42:41.600 11208-11208/com.felix.testrxjava E/retryWhen: index 102-08 11:42:44.601 11208-11582/com.felix.testrxjava E/retryWhen: index 202-08 11:42:47.599 11208-11582/com.felix.testrxjava E/retryWhen: index 3...<div class="se-preview-section-delimiter"></div>
注意:retry/retryWhen操作符默认在trampoline调度器上执行。
12 辅助操作符
12.1 delay/delaySubscription
delay操作符让原始Observable在发射每项数据之前都暂停一段指定的时间段。效果是Observable发射的数据项在时间上向前整体平移了一个增量。
注意:delay不会平移onError通知,它会立即将这个通知传递给订阅者,同时丢弃任何待发射的onNext通知。然而它会平移一个onCompleted通知。
第一种 delay接受一个定义时长的参数(包括数量和单位)。每当原始Observable发射一项数据,delay就启动一个定时器,当定时器过了给定的时间段时,delay返回的Observable发射相同的数据项,这种delay默认在computation调度器上执行
Observable.create(subscriber -> { for (int i = 0; i < 3; i++) { subscriber.onNext("index" + i); } if (new Random().nextBoolean()) { subscriber.onError(new Exception("error")); }else { subscriber.onCompleted(); } }).delay(2, TimeUnit.SECONDS).cast(String.class) .subscribe(str -> Log.e("delay", str), throwable ->Log.e("delay", throwable.getMessage()), ()->Log.e("delay", "onCompleted"));<div class="se-preview-section-delimiter"></div>
因为加了随机函数,点击了三次,打印结果如下:
02-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: index002-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: index102-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: index202-13 22:48:37.735 13059-13715/com.felix.testrxjava E/delay: onCompleted02-13 22:48:39.034 13059-13349/com.felix.testrxjava E/delay: --error--02-13 22:48:42.322 13059-13368/com.felix.testrxjava E/delay: --error--<div class="se-preview-section-delimiter"></div>
第二种delay不是用常数参数,而是使用一个函数 Func1 针对原始Observable的每一项数据返回一个Observable,它监视返回的这个Observable,当任何那样的Observable终止时,delay返回的Observable就发射关联的那项数据。这种delay默认不在任何特定的调度器上执行
Observable.just("a", "b", "c") .delay(index -> { return Observable.just(index).delay(x++, TimeUnit.SECONDS); }).subscribe(str -> Log.e("delay2", str), throwable -> Log.e("delay2", throwable.getMessage()), () -> Log.e("delay2", "onCompleted")); <div class="se-preview-section-delimiter"></div>
返回结果如下
02-13 23:19:39.189 27635-27917/com.felix.testrxjava E/delay2: a02-13 23:19:40.190 27635-27918/com.felix.testrxjava E/delay2: b02-13 23:19:41.190 27635-27919/com.felix.testrxjava E/delay2: c02-13 23:19:41.190 27635-27919/com.felix.testrxjava E/delay2: onCompleted<div class="se-preview-section-delimiter"></div>
第三种delay对每一项数据使用一个Observable作为原始Observable的延时定时器。这种delay默认不在任何特定的调度器上执行。
12.2 Materialize/Dematerialize
Materialize将数据项和事件通知都当做数据项发射,Dematerialize刚好相反。
materialize将来自原始Observable的通知转换为Notification对象,然后它返回的Observable会发射这些数据;dematerialize反转这个过程,将原始Observable发射的Notification对象还原成Observable的通知。
12.3 serialize
强制一个Observable连续调用并保证行为正确。主要用于多线程调用的时候,保证rxjava的正确性。
12.4 timeout
- timeout(long,TimeUnit))
每当原始Observable发射了一项数据,timeout就启动一个计时器,如果计时器超过了指定指定的时长而原始Observable没有发射另一项数据,timeout就抛出TimeoutException,以一个错误通知终止Observable。它默认在computation调度器上执行。
- timeout(long,TimeUnit,Observable))
在超时时会切换到使用一个你指定的备用的Observable,而不是发错误通知。它也默认在computation调度器上执行。
- timeout(Func1))
使用一个函数针对原始Observable的每一项返回一个Observable,如果当这个Observable终止时原始Observable还没有发射另一项数据,就会认为是超时了,timeout就抛出TimeoutException,以一个错误通知终止Observable。这个timeout默认在immediate调度器上执行。
- timeout(Func1,Observable))
同时指定超时时长和备用的Observable。它默认在immediate调度器上执行。
- timeout(Func0,Func1))
除了给每一项设置超时,还可以单独给第一项设置一个超时。它默认在immediate调度器上执行。
12.5 timestamp
将一个发射T类型数据的Observable转换为一个发射类型为Timestamped的数据的Observable,每一项都包含数据的原始发射时间。timestamp默认在immediate调度器上执行.
public void timestamp(View view) { Observable.interval(1000, TimeUnit.MILLISECONDS) .take(4) .timestamp() .subscribe(ts -> LogUtils.e(ts.getTimestampMillis() + "--" + ts.getValue())); }}<div class="se-preview-section-delimiter"></div>
将结果转换了,增加了一个时间戳标志。
02-18 00:53:00.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350380181--002-18 00:53:01.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350381181--102-18 00:53:02.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350382180--202-18 00:53:03.181 19330-19555/com.felix.testrxjava E/LogUtils: 1487350383180--3<div class="se-preview-section-delimiter"></div>
13 do
注册一个动作作为原始Observable生命周期事件的一种占位符,你可以注册回调,当Observable的某个事件发生时,Rx会在与Observable链关联的正常通知集合中调用它。
13.1 doOnEach
doOnEach操作符让你可以注册一个回调,它产生的Observable每发射一项数据就会调用它一次。也就是onNext,onError,onCompleted三个回调都会触发doOnEach回调其响应的方法。你可以以Action的形式传递参数给它,这个Action接受一个onNext的变体Notification作为它的唯一参数,你也可以传递一个Observable给doOnEach,这个Observable的onNext会被调用,就好像它订阅了原始的Observable一样。
Observable.just(1, 2, 3) .doOnEach(notification -> { Log.e("---", notification.getKind() + " --" + notification.getValue() + "_" + notification.isOnNext() + "_" + notification.isOnCompleted()); }) .subscribe(str -> Log.e("doOnEach", str + ""));<div class="se-preview-section-delimiter"></div>
可以看出来Notification包含了当前Observable的各种状态,返回值如下:
02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnNext --1_true_false02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/doOnEach: 102-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnNext --2_true_false02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/doOnEach: 202-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnNext --3_true_false02-14 21:13:29.058 25118-25118/com.felix.testrxjava E/doOnEach: 302-14 21:13:29.058 25118-25118/com.felix.testrxjava E/---: OnCompleted --null_false_true<div class="se-preview-section-delimiter"></div>
doOnEach还有一个实现方式
Observable.just(11, 22, 33, 44) .doOnEach(new Observer<Integer>() { @Override public void onCompleted() { Log.e("doOnEach2--", "onCompleted"); } @Override public void onError(Throwable e) { Log.e("doOnEach2--", "e " + e.getMessage()); } @Override public void onNext(Integer integer) { Log.e("doOnEach2--", "integer " + integer); } }) .subscribe(str -> Log.e("doOnEach2", str + ""));<div class="se-preview-section-delimiter"></div>
我们通过返回值看出来,回调了Observer的onNext方法。
02-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 1102-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 1102-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 2202-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 2202-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 3302-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 3302-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onNext 4402-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2: 4402-15 08:17:06.021 501-501/com.felix.testrxjava E/doOnEach2--: onCompleted<div class="se-preview-section-delimiter"></div>
13.2 doOnNext/doOnCompleted/doOnError
doOnNext操作符类似于doOnEach(Action1),但是它的Action不是接受一个Notification参数,而是接受发射的数据项。只有onNext回调的时候回触发doOnNext
public void doOnNext(View view) { Observable.just(1, 2, 3) .doOnNext(integer -> Log.e("doOnNext", "doOnNext " + integer)) .subscribe(str -> Log.e("doOnNext", str + ""));}<div class="se-preview-section-delimiter"></div>
我们看看输出,会同时调用doOnNext 和订阅方法,且接收到的数据也是一样的
02-15 10:01:29.471 1975-1975/com.felix.testrxjava E/doOnNext: doOnNext 102-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: 102-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: doOnNext 202-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: 202-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: doOnNext 302-15 10:01:29.472 1975-1975/com.felix.testrxjava E/doOnNext: 3<div class="se-preview-section-delimiter"></div>
doOnCompleted/doOnError和doOnNext类似,只有在相应的方法调用的时候才会调用此方法。
13.3 doOnSubscribe/doOnUnsubscribe
doOnSubscribe,当观察者订阅它生成的Observable它就会被调用。
doOnUnsubscribe,当观察者取消订阅它生成的Observable它就会被调用。
public void doOnSubscribe(View view) { Subscription subscription = Observable.just(1, 2, 3) .doOnSubscribe(() -> Log.e("doOnSubscribe", "Subscribe")) .doOnUnsubscribe(() -> Log.e("doOnUnsubscribe", "Unsubscribe")) .subscribe(); if (!subscription.isUnsubscribed()) { subscription.unsubscribe(); }}<div class="se-preview-section-delimiter"></div>
看一下输出结果
02-15 10:15:22.149 23724-23724/com.felix.testrxjava E/doOnSubscribe: Subscribe02-15 10:15:22.149 23724-23724/com.felix.testrxjava E/doOnUnsubscribe: Unsubscribe<div class="se-preview-section-delimiter"></div>
13.3 doOnTerminate/doAfterTerminate
doOnTerminate 操作符注册一个动作,当它产生的Observable终止之前会被调用,无论是正常还是异常终止。
doAfterTerminate 操作符注册一个动作,当它产生的Observable终止之后会被调用,无论是正常还是异常终止。
public void doOnTerminate(View view) { Observable.create(subscriber -> { if (new Random().nextBoolean()) { subscriber.onNext("aa"); subscriber.onCompleted(); } subscriber.onNext("bb"); subscriber.onError(new Exception("bb error")); }).doOnTerminate(() -> Log.e("doOnTerminate", "OnTerminate")) .doAfterTerminate(() -> Log.e("doAfterTerminate", "AfterTerminate")) .cast(String.class) .subscribe(str -> Log.e("", str), e -> Log.e("", e.getMessage()));}<div class="se-preview-section-delimiter"></div>
可以看出来,因为用了随机函数,可能出现这两种中的一种。但不管成功还是失败,都是一个是在会调前调用,一个是在回调后调用。
02-15 10:29:41.935 14858-14858/com.felix.testrxjava E/doOnTerminate: OnTerminate02-15 10:29:41.935 14858:14858 E/ bb error02-15 10:29:41.935 14858-14858/com.felix.testrxjava E/doAfterTerminate: AfterTerminate02-15 10:30:54.859 14858-14858/com.felix.testrxjava E/doAfterTerminate: AfterTerminate02-15 10:31:01.661 14858-14858/com.felix.testrxjava E/doOnTerminate: OnTerminate02-15 10:31:01.661 14858-14858/com.felix.testrxjava E/doAfterTerminate: AfterTerminate<div class="se-preview-section-delimiter"></div>
14 BlockingObservable
使用 BlockingObservable 可以把 Observable 中的数据通过阻塞的方式发射出来。任何一个 Observable 都可以使用下面两种方式来转换为阻塞的 Observable。
BlockingObservable.fromObservable.toBlocking<div class="se-preview-section-delimiter"></div>
14.1 getIterator
将observable转成数据结果iterator类型,然后可以按iterator来获取数据。是阻塞式的,当有observable发出时才会输出数据。
getIterator操作符只能用于BlockingObservable以及它的子类
public void getIterator(View view) { Iterator it = BlockingObservable.from(Observable.interval(1, TimeUnit.SECONDS).take(5)) .getIterator(); while (it.hasNext()) { LogUtils.e(it.next().toString()); }}<div class="se-preview-section-delimiter"></div>
14.2 toList
将Observable转成数据类型list,阻塞式。通常,发射多项数据的Observable会为每一项数据调用onNext方法。你可以用toList操作符改变这个行为,让Observable将多项数据组合成一个List,然后调用一次onNext方法传递整个列表。
如果原始Observable没有发射任何数据就调用了onCompleted,toList返回的Observable会在调用onCompleted之前发射一个空列表。如果原始Observable调用了onError,toList返回的Observable会立即调用它的观察者的onError方法。
14.3 toSortedList
toSortedList类似于toList,不同的是,它会对产生的列表排序,默认是自然升序,如果发射的数据项没有实现Comparable接口,会抛出一个异常。然而,你也可以传递一个函数作为用于比较两个数据项,这是toSortedList不会使用Comparable接口。
14.2 toIterable
把 Observable 转换为 iterables ,阻塞式。然后可以传统的 Java 方式来遍历这些集合。当需要处理数据的时候,就调用 Iterator 的 next() 函数,如果有数据 next() 就直接返回;如果没有数据 next() 函数就阻塞直到有数据产生。
toIterable操作符只能用于BlockingObservable以及它的子类
14.3 toFuture
将Observable转换为一个返回单个数据项的Future,非阻塞式。如果原始Observable发射多个数据项,Future会收到一个IllegalArgumentException;如果原始Observable没有发射任何数据,Future会收到一个NoSuchElementException。如果你想将发射多个数据项的Observable转换为Future,可以这样用:myObservable.toList().toBlocking().toFuture()。
toFuture操作符只能用于BlockingObservable以及它的子类
14.4 toMap
toMap收集原始Observable发射的所有数据项到一个Map(默认是HashMap)然后发射这个Map。你可以提供一个用于生成Map的Key的函数,还可以提供一个函数转换数据项到Map存储的值(默认数据项本身就是值)
public void toMap(View view) { Observable.just("a", "b", "c") .toMap(s -> s + "-", s -> s + "=", ()->new HashMap<String, String>(3)) .subscribe(LogUtils::e); }}public final static <K, V> void e(Map<K, V> maps) { for (Map.Entry entry : maps.entrySet()) { e("key:" + entry.getKey() + " value: " + entry.getValue()); }}<div class="se-preview-section-delimiter"></div>
输出如下,可以看出来,第一个函数产生key,第二个参数产生value(无此参数则使用发射的值),第三个参数则是一个map工厂用于创建一个map以存储值。
02-19 23:03:06.583 15523-15523/com.felix.testrxjava E/LogUtils: c--- +++ c02-19 23:03:06.583 15523-15523/com.felix.testrxjava E/LogUtils: a--- +++ a02-19 23:03:06.583 15523-15523/com.felix.testrxjava E/LogUtils: b--- +++ b<div class="se-preview-section-delimiter"></div>
14.5 toMultiMap
toMultiMap类似于toMap,不同的是,它生成的这个Map同时还是一个ArrayList(默认是这样,你可以传递一个可选的工厂方法修改这个行为)
14.6 nest
将一个Observable转换为一个发射这个Observable的Observable.
public void nest(View view) { Observable.just(1, 2, 3, 4, 5).nest() .subscribe(observable -> observable.subscribe(LogUtils::e));}<div class="se-preview-section-delimiter"></div>
打印结果如下:
02-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils: 102-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils: 202-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils: 302-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils: 402-19 23:02:07.954 15523-15523/com.felix.testrxjava E/LogUtils: 5<div class="se-preview-section-delimiter"></div>
15 条件和布尔操作符
15.1 all
传递一个谓词函数给all操作符,这个函数接受原始Observable发射的数据,根据计算返回一个布尔值。All返回一个只发射一个单个布尔值的Observable,如果原始Observable正常终止并且每一项数据都满足条件,就返回true;如果原始项数据都满足条件,就返回true;如果原始Observable的任何一项数据不满足条件就返回False。
Observable.just(5, 6, 7, 8, 9) .all(integer -> integer > 4) .subscribe(LogUtils::e);}public final static void e(boolean flag) { Log.e(TAG, flag ? "true" : "false"); }<div class="se-preview-section-delimiter"></div>
15.2 amb/ambWith
当你传递多个Observable给amb时,它只发射其中一个Observable的数据和通知:首先发送通知给amb的那个,不管发射的是一项数据还是一个onError或onCompleted通知。Amb将忽略和丢弃其它所有Observables的发射物。
public void amb(View view) { Observable.amb(Observable.create(subscriber -> { SystemClock.sleep(200); subscriber.onNext(1); subscriber.onCompleted(); }).subscribeOn(Schedulers.newThread()), Observable.create(subscriber -> { SystemClock.sleep(100); subscriber.onError(new Exception("error")); subscriber.onCompleted(); }).subscribeOn(Schedulers.newThread())) .cast(Integer.class).subscribe(LogUtils::e, LogUtils::e);}<div class="se-preview-section-delimiter"></div>
15.3 contains
给contains传一个指定的值,如果原始Observable发射了那个值,它返回的Observable将发射true,否则发射false。
public void contains(View view) { Observable.create(subscriber -> { for (int i = 0; i < 5; i++) { subscriber.onNext(i); SystemClock.sleep(200); } }).contains(3) .subscribe(LogUtils::e);}<div class="se-preview-section-delimiter"></div>
15.4 exists
通过一个谓词函数测试原始Observable发射的数据,只要任何一项满足条件就返回一个发射true的Observable,否则返回一个发射false的Observable。
15.5 isEmpty
用于判定原始Observable是否没有发射任何数据。
public void isEmpty(View view) { Observable.empty().isEmpty().subscribe(LogUtils::e); Observable.just(12, 3).isEmpty().subscribe(LogUtils::e); Observable.error(new Exception("error")).isEmpty().subscribe(LogUtils::e, LogUtils::e);}<div class="se-preview-section-delimiter"></div>
从下面输出可以看出来,如果原Observable抛出一个异常,则会直接调用onError,而不会走isEmpty方法
02-20 08:28:49.236 29580-29580/com.felix.testrxjava E/LogUtils: true02-20 08:28:49.237 29580-29580/com.felix.testrxjava E/LogUtils: false02-20 08:28:49.238 29580-29580/com.felix.testrxjava E/LogUtils: throwable: error
15.6 defaultIfEmpty
defaultIfEmpty简单的精确地发射原始Observable的值,如果原始Observable没有发射任何数据正常终止(以onCompleted的形式),defaultIfEmpty返回的Observable就发射一个你提供的默认值。
15.7 sequenceEqual
传递两个Observable给SequenceEqual操作符,它会比较两个Observable的发射物,如果两个序列是相同的(相同的数据,相同的顺序,相同的终止状态),它就发射true,否则发射false。第三个参数,可以传递一个函数用于比较两个数据项是否相同.
15.8 skipUntil
skipUntil订阅原始的Observable,但是忽略它的发射物,直到第二个Observable发射了一项数据那一刻,它开始发射原始Observable。
15.9 skipWhile
skipWhile订阅原始的Observable,但是忽略它的发射物,直到你指定的某个条件变为false的那一刻,它开始发射原始Observable。
15.10 takeUntil
takeUntil订阅并开始发射原始Observable,它还监视你提供的第二个Observable。如果第二个Observable发射了一项数据或者发射了一个终止通知,takeUntil返回的Observable会停止发射原始Observable并终止。第二个Observable发射一项数据或一个onError通知或一个onCompleted通知都会导致takeUntil停止发射数据。
还有一个版本的takeUntil,不在RxJava 1.0.0版中,它使用一个谓词函数而不是第二个Observable来判定是否需要终止发射数据,它的行为类似于takeWhile。
15.11 takeWhile
takeWhile操作符返回一个镜像原始Observable行为的Observable,直到某一项数据你指定的函数返回false那一刻,这个新的Observable发射onCompleted终止通知。
- RxAndroid使用文档(New)
- RXAndroid Single的使用
- RxAndroid使用入门记录
- Rxjava RxAndroid 使用
- RxAndroid之Rxlifecycle使用
- RxJava漫谈-RxAndroid使用
- Retrofit + RxAndroid的使用
- Android RxAndroid使用
- RxAndroid的使用
- RxAndroid之Rxlifecycle使用
- RxAndroid的使用
- Retrofit2、okHttp3、RxAndroid使用
- Android RxAndroid使用
- RxAndroid之Rxlifecycle使用
- RxAndroid 的使用方式
- RxAndroid之Rxlifecycle使用
- RxAndroid
- RxAndroid
- Mac OS X中配置Apache
- Java反射机制详解
- 30组常用前端开发组件库,前端组件收集整理列表
- Android studio svn 忽略文件
- group by在mysql和oracle中的区别
- RxAndroid使用文档(New)
- 1066. 图像过滤(15)
- poj 3710 Christmas Game(博弈 无向图删边游戏)
- IIC
- 数据库优化---空间换时间优化
- C primer plus 第八章 字符输入输出与输入验证 编程练习 个人答案
- java 类型信息
- Android开发——Bitmap(位图)全方位解析(一)
- jdk1.8 LongAdder源码学习