简单记录一些基础知识和使用方法,目标——简单!能用!
Github地址:
https://github.com/ReactiveX/RxJava
https://github.com/ReactiveX/RxAndroid
依赖库:
implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
使用场景:异步!
实现原理:观察者模式!
简单用:
Observable | 被观察者 |
Observer | 观察者 |
不管怎么样,来个例子:
//创建被观察者
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) {
emitter.onNext("G1");
emitter.onNext("G2");
emitter.onComplete();
}
}).subscribe( new Observer<String>() {//创建观察者并订阅
private Disposable mDisposable;
@Override
public void onSubscribe(Disposable d) {
Log.v(TAG, "onSubscribe");
mDisposable = d;
}
@Override
public void onNext(String s) {
Log.v(TAG, "onNext:" + s);
if("ok".equals(s)) {
mDisposable.dispose();
}
}
@Override
public void onError(Throwable e) {
Log.v(TAG, "onError:" + e);
}
@Override
public void onComplete() {
Log.v(TAG, "onComplete");
}
});
被观察者Observable被创建后,可以通过ObservableEmitter发数据;
观察者Observer的接口中可以收到ObservableEmitter发送的数据;
通过subscribe方法,给被观察者Observable指定观察者Observer;
数据发射器ObservableEmitter;
数据发射器ObservableEmitter方法有3个:
- onNext:发送数据;
- onError:发送错误消息;
- onComplete:发送完成,调用之后再调用onNext观察者Observer也不会收到消息;
数据会被发射到对应的观察者Observer的接口中;
示例中的代码,运行后LOG如下:
V/x999x: onSubscribe
V/x999x: onNext:G1
V/x999x: onNext:G2
V/x999x: onComplete
观察者Observer的onSubscribe接口会最先被调用;
而G3消息如预期一样,没有被送达;
onSubscribe接口中提供了一个Disposable对象,可以调用dispose方法中断消息发送;
修改subscribe方法代码如下:
emitter.onNext("G1");
emitter.onNext("ok");
emitter.onNext("G2");
emitter.onComplete();
emitter.onNext("G3");
再次运行后,LOG如下:
V/x999x: onSubscribe
V/x999x: onNext:G1
V/x999x: onNext:ok
调用dispose方法后,onNext和onComplete都不再执行;
最后再测试一下onError方法,修改subscribe方法代码如下:
emitter.onNext("G1");
emitter.onError(new Throwable("GOOD GAME!"));
emitter.onNext("ok");
emitter.onNext("G2");
emitter.onComplete();
emitter.onNext("G3");
再次运行后,LOG如下:
V/x999x: onSubscribe
V/x999x: onNext:G1
V/x999x: onError:java.lang.Throwable: GOOD GAME!
发送onError消息,onNext和onComplete都将不再发送;
这里需要提一点,在通过dispose中断消息后,在调用onError运行会报错!
所以调用onError消息前最好判断一下,修改subscribe方法代码如下:
emitter.onNext("G1");
emitter.onNext("ok");
if (!emitter.isDisposed()) {
emitter.onError(new Throwable("GOOD GAME!"));
}
emitter.onNext("G2");
emitter.onComplete();
emitter.onNext("G3");
上述代码,如果去掉isDisposed会直接运行报错!
被观察者的创建方式:
Rxjava创建一个被观察者是第一步!
除了Observable.create以外,还有多种创建被观察者的方式:
create | 最基本的创建方式,也是我们最初示例里面用的方式 |
just | 一种快速的创建方式,直接将需要发射的内容作为参数传入,参数上限是10个; |
fromArray | 逐个发送传入传入的内容;和just的区别是没有上限; |
fromIterable | 逐个发送传入的迭代器中的元素;常见的如传入一个List作为参数; |
fromPublisher | 从一个Pusblisher中创建 |
fromCallable | 从一个Callable中创建 |
fromFuture | 从一个Future中创建 |
-
create
最基本创建Observable的方式。这个在之前的示例中已经用到,不再重复。
-
just
一种快速的创建方式,直接将需要发射的内容作为参数传入,参数上限是10个;
Observable.just(1, 2, 3)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log("onNext-" + integer);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
x999x:onSubscribe
x999x:onNext-1
x999x:onNext-2
x999x:onNext-3
x999x:onComplete
-
fromArray
逐个发送传入传入的内容;和just的区别是没有上限;
Observable.fromArray(1, 2, 3)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log("onNext-" + integer);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
从这个代码来看和just没有任何区别,其实从源码看,传入多个参数的just调用的就是fromArray方法;
x999x:onSubscribe
x999x:onNext-1
x999x:onNext-2
x999x:onNext-3
x999x:onComplete
-
fromIterable
逐个发送传入的迭代器中的元素;常见的如传入一个List作为参数;
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(2);
list.add(1);
Observable.fromIterable(list)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log("onNext-" + integer);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
东西比较容易理解,所以换了一下发射的顺序,免得LOG看着像是复制粘贴的...
x999x:onSubscribe
x999x:onNext-3
x999x:onNext-2
x999x:onNext-1
x999x:onComplete
-
fromPublisher
从一个Pusblisher中创建。
Rxjava中定义了很多实现Publisher接口的对象,使用Ctril+Alt+B,可以找到他们。
其中最基础的就是被观察者Flowable,和被观察者Observable的区别是支持背压式,背压式具体会在后面做介绍。
这里来个简单的例子:
Observable.fromPublisher(new Flowable<Integer>() {
@Override
protected void subscribeActual(Subscriber s) {
s.onNext(3);
s.onNext(6);
s.onNext(9);
s.onComplete();
}
}).subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log("onNext-" + integer);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
x999x:onNext-3
x999x:onNext-6
x999x:onNext-9
x999x:onComplete
仔细观察log,还是有一些小区别的,onSubscribe没有被调用,在使用Flowable时,onSubscribe也需要手动调用;
示例:
Observable.fromPublisher(new Flowable<Integer>() {
@Override
protected void subscribeActual(Subscriber s) {
s.onSubscribe(new Subscription() {
@Override
public void request(long n) {
}
@Override
public void cancel() {
}
});
s.onNext(3);
s.onNext(6);
s.onNext(9);
s.onComplete();
}
}).subscribe(new Observer<Integer>() {
//省略一长串
}
-
fromCallable
从一个Callable中创建
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Log("Callable:call");
Thread.sleep(2000);
return "Hello";
}
};
Observable.fromCallable(callable)
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(String s) {
Log("onNext-" + s);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
因为例子比较简单,所以加了延迟,这样看着更有意思一些,顺序改造了一下Test里面Log输出,在Log中加入了时间信息;
2019-11-29 11:30:45 x999x:onSubscribe
2019-11-29 11:30:45 x999x:Callable:call
2019-11-29 11:30:47 x999x:onNext-Hello
2019-11-29 11:30:47 x999x:onComplete
可能有同学对Callable不是很熟悉的,可以先做下了解,它是属于Java 多线程的一部分。
-
fromFuture
从一个Future中创建
此方法由四个重载:
public static <T> Observable<T> fromFuture(Future<? extends T> future)
public static <T> Observable<T> fromFuture(Future<? extends T> future, long timeout, TimeUnit unit)
public static <T> Observable<T> fromFuture(Future<? extends T> future, long timeout, TimeUnit unit, Scheduler scheduler)
public static <T> Observable<T> fromFuture(Future<? extends T> future, Scheduler scheduler)
遇到这种情况,通常来说看参数最多的就可以了;
future:数据源
timeout:超时时间
unit:超时时间的单位
scheduler:将future运行在指定的scheduler上
这里改造一下之前callable的示例:
// 创建Callable
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Log("call");
Thread.sleep(2000);
return "Hello";
}
};
// 创建ExecutorService,通过submit得到Future
Future future = Executors.newSingleThreadExecutor().submit(callable);
// 创建Executor,这个Executor用来创建Scheduler
Executor executor = new Executor() {
@Override
public void execute(Runnable command) {
Log("Scheduler: execute");
command.run();
}
};
// 创建Scheduler
Scheduler scheduler = Schedulers.from(executor);
// 开搞!
Observable.fromFuture(
future,
5,
TimeUnit.SECONDS,
scheduler
)
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(Object o) {
Log("Observer:onNext-" + o);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
当超时时间设置为5秒时:
2019-11-29 14:41:17 x999x:call
2019-11-29 14:41:17 x999x:Observer: onSubscribe
2019-11-29 14:41:17 x999x:Scheduler: execute
2019-11-29 14:41:19 x999x:Observer:onNext-Hello
2019-11-29 14:41:19 x999x:Observer:onComplete
当超时时间设置为1秒时:
2019-11-29 14:46:20 x999x:call
2019-11-29 14:46:20 x999x:Observer: onSubscribe
2019-11-29 14:46:20 x999x:Scheduler: execute
2019-11-29 14:46:21 x999x:Observer:onError
这可以看到,当获取future结果的时间超过timeout时,观察者会接收到onError回调!
这里做了小实验,验证了一下Scheduler,把executor里面command.run();注释掉,则不会收到future的结果。
可能有同学对future不是很熟悉的,可以先做下了解,它是属于Java 多线程的一部分。
Scheduler是Rxjava任务调度的内容,后面会有涉及。
定线程:
subscribeOn | 指定消息发送者(被观察者)的线程,只能指定一次,多次指定,只第一次起效 |
observeOn | 指定观察者的线程,可多次指定 |
来个例子:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) {
Log.v(TAG, "Observable thread is : " + Thread.currentThread().getName());
emitter.onNext("Go Go Go");
emitter.onComplete();
}
}).subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.v(TAG, "Consumer mainThread is : " + Thread.currentThread().getName());
Log.v(TAG,"accept=" + s);
}
})
.observeOn(Schedulers.io())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
Log.v(TAG, "Consumer io Thread is : " + Thread.currentThread().getName());
Log.v(TAG,"accept=" + s);
}
});
运行结果:
V/x999x: Observable thread is : RxNewThreadScheduler-1
V/x999x: Consumer mainThread is : main
V/x999x: accept=Go Go Go
V/x999x: Consumer io Thread is : RxCachedThreadScheduler-2
V/x999x: accept=Go Go Go
从例子中可以看到,观察者可以有多个;
观察者除了Observer之外还有一个简化的版本消费者——Consumer!
常用线程一共分为以下几种,根据需求可以选择:
AndroidSchedulers.mainThread() | 代表Android的主线程 |
Schedulers.newThread() | 代表一个常规的新线程 |
Schedulers.io() | 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作 |
Schedulers.computation() | 代表CPU计算密集型的操作, 例如需要大量计算的操作 |
数据处理:
map | 当被观察者提供的数据和观察者使用的数据需要某种转换的时候可以用用它 |
zip | 将两个被观察者的数据合二为一 |
concat | 把两个发射器连接成一个发射器 |
buffer | 操作符接受两个参数,buffer(count,skip),作用是将 Observable 中的数据按 skip (步长) 分成最大不超过count的buffer ,然后生成一个Observable |
filter | 过滤器,可以接受一个参数,让其过滤掉不符合我们条件的值 |
distinct | 去重复 |
flatMap | 把一个发射器Observable通过某种方法转换为多个Observables,然后再把这些分散的Observables装进一个单一的发射器Observable。但有个需要注意的是,flatMap 并不能保证事件的顺序 |
concatMap | concatMap与FlatMap的唯一区别就是concatMap保证了顺序 |
debounce | 去除发送频率过快的项 |
last | 仅取出可观察到的最后一个值,或者是满足某些条件的最后一项 |
merge | 把多个Observable结合起来,接受可变参数,也支持迭代器集合。它和concat的区别在于,不用等到 发射器 A 发送完所有的事件再进行发射器 B 的发送 |
reduce | 每次用一个方法处理一个值,可以有一个 seed 作为初始值 |
scan | 操作符作用和上面的 reduce 一致,唯一区别是 reduce 只追求结果,而 scan 会始终如一地把每一个步骤都输出。 |
window | 按照实际划分窗口,将数据发送给不同的 Observable |
take | 接受一个 long 型参数 count ,代表至多接收 count 个数据 |
-
map
当被观察者提供的数据和观察者使用的数据需要某种转换的时候可以用用它;
来个例子:
class Person{
String name;
public Person(String name) {
this.name = name;
}
@Override
public String toString() {
return "My name is " + name;
}
}
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) {
emitter.onNext("Liu Bei");
emitter.onNext("Guan Yu");
emitter.onNext("Zhang Fei");
}
}).map(new Function<String, Person>() {
@Override
public Person apply(String s) {
return new Person(s);
}
}).subscribe(new Consumer<Person>() {
@Override
public void accept(Person person) throws Exception {
Log.d(TAG, person.toString());
}
});
运行LOG如下:
D/x999x: My name is Liu Bei
D/x999x: My name is Guan Yu
D/x999x: My name is Zhang Fei
-
zip
将两个被观察者的数据合二为一;这个东西实际使用中没试过;
数据配对是严格按照发射数据的顺序的;
如果双方数据长度不一致,按短的那个来;
举个例子:
Observable observable1 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) {
emitter.onNext("Liu Bei");
emitter.onNext("Guan Yu");
emitter.onNext("Zhang Fei");
}
});
Observable observable2 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) {
emitter.onNext("Da Ge");
emitter.onNext("Er Ge");
emitter.onNext("San Di");
emitter.onNext("Si Di");
}
});
Observable.zip(observable1, observable2, new BiFunction<String, String, String>() {
@Override
public String apply(String o, String o2) throws Exception {
return o + " is " + o2;
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String o) throws Exception {
Log.v(TAG, o);
}
});
运行后LOG:
V/x999x: Liu Bei is Da Ge
V/x999x: Guan Yu is Er Ge
V/x999x: Zhang Fei is San Di
无论运行多少次,刘备都是大哥,四弟也永远出不来!
-
concat
把几个发射器连接成一个发射器,最多支持输入4个参数!
Observable<Integer> o1 = Observable.fromArray(1, 2, 3);
Observable<Integer> o2 = Observable.fromArray(4, 5, 6);
Observable<Integer> o3 = Observable.fromArray(7, 0, 0);
Observable.concat(o1, o2, o3)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(Integer o) {
Log("Observer:onNext-" + o);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
2019-11-29 15:41:39 x999x:Observer: onSubscribe
2019-11-29 15:41:39 x999x:Observer:onNext-1
2019-11-29 15:41:39 x999x:Observer:onNext-2
2019-11-29 15:41:39 x999x:Observer:onNext-3
2019-11-29 15:41:39 x999x:Observer:onNext-4
2019-11-29 15:41:39 x999x:Observer:onNext-5
2019-11-29 15:41:39 x999x:Observer:onNext-6
2019-11-29 15:41:39 x999x:Observer:onNext-7
2019-11-29 15:41:39 x999x:Observer:onNext-0
2019-11-29 15:41:39 x999x:Observer:onNext-0
2019-11-29 15:41:39 x999x:Observer:onComplete
这里还有几个变种:
* concatArray:这个方法消除了参数个数限制
public static <T> Observable<T> concatArray(ObservableSource<? extends T>... sources)
* concatArrayDelayError:这个方法会忽略中间遇到的error
public static <T> Observable<T> concatArrayDelayError(ObservableSource<? extends T>... sources)
* concatArrayEager:急切模式
public static <T> Observable<T> concatArrayEager(int maxConcurrency, int prefetch, ObservableSource<? extends T>... sources)
* concatArrayEagerDelayError:忽略error的急切模式
public static <T> Observable<T> concatArrayEagerDelayError(int maxConcurrency, int prefetch, ObservableSource<? extends T>... sources)
这里先给concatArrayDelayError举个例子:
正常情况下的出现Error:
Observable<Integer> o1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onError(new Throwable("E"));
emitter.onNext(2);
emitter.onNext(3);
}
});
Observable<Integer> o2 = Observable.fromArray(4, 5, 6);
Observable.concatArray(o1, o2)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(Integer o) {
Log("Observer:onNext-" + o);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
2019-11-29 16:09:31 x999x:Observer: onSubscribe
2019-11-29 16:09:31 x999x:Observer:onNext-1
2019-11-29 16:09:31 x999x:Observer:onError
使用DelayError时出现Error:
Observable<Integer> o1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onError(new Throwable("E"));
emitter.onNext(2);
emitter.onNext(3);
}
});
Observable<Integer> o2 = Observable.fromArray(4, 5, 6);
Observable.concatArrayDelayError(o1, o2,)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(Integer o) {
Log("Observer:onNext-" + o);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
2019-11-29 16:09:06 x999x:Observer: onSubscribe
2019-11-29 16:09:06 x999x:Observer:onNext-1
2019-11-29 16:09:06 x999x:Observer:onNext-4
2019-11-29 16:09:06 x999x:Observer:onNext-5
2019-11-29 16:09:06 x999x:Observer:onNext-6
2019-11-29 16:09:06 x999x:Observer:onError
可以看到,在使用concatArrayDelayError时,虽然第一个Observable发生了error,但依然完成了第二个Observable的数据发射。
然后再看看所谓的急切模式,怕解释的不好,下面是官方注释:
/**
* Concatenates an array of {@link ObservableSource}s eagerly into a single stream of values
* and delaying any errors until all sources terminate.
* <p>
* <img width="640" height="460" src="https://raw.github.com/wiki/ReactiveX/RxJava/images/rx-operators/concatArrayEagerDelayError.nn.png" alt="">
* <p>
* Eager concatenation means that once a subscriber subscribes, this operator subscribes to all of the
* source {@code ObservableSource}s. The operator buffers the values emitted by these {@code ObservableSource}s
* and then drains them in order, each one after the previous one completes.
* <dl>
* <dt><b>Scheduler:</b></dt>
* <dd>This method does not operate by default on a particular {@link Scheduler}.</dd>
* </dl>
* @param <T> the value type
* @param sources an array of {@code ObservableSource}s that need to be eagerly concatenated
* @param maxConcurrency the maximum number of concurrent subscriptions at a time, Integer.MAX_VALUE
* is interpreted as indication to subscribe to all sources at once
* @param prefetch the number of elements to prefetch from each {@code ObservableSource} source
* @return the new Observable instance with the specified concatenation behavior
* @since 2.2.1 - experimental
*/
大概的意思是,在急切模式下,不再一个个订阅传入的Observable了,而是一下子全部订阅了,然后先完成的放入缓存,当轮到输出的时候,Biu!一下子把缓存了的输出去。
看样子是能加快速度的,不过用到缓存可能对内存压力会比较大,没在具体项目中做过测试,不敢断言。
-
buffer
把输出的数据分割成符合要求的多个List
大体可以有两类:数量、时间
这个举个简单例子:
Observable.fromArray(1,2,3,4,5)
.buffer(3)
.subscribe(new Observer<List<Integer>>() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(List<Integer> integers) {
Log("Observer:onNext-" + integers);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
2019-11-29 16:27:20 x999x:Observer: onSubscribe
2019-11-29 16:27:20 x999x:Observer:onNext-[1, 2, 3]
2019-11-29 16:27:20 x999x:Observer:onNext-[4, 5]
2019-11-29 16:27:20 x999x:Observer:onComplete
-
filter
过滤器,过滤掉不符合要求的数据,这个很简单,直接看例子
Observable.fromArray(1,2,3,4,5)
.filter(new Predicate<Integer>() {
@Override
public boolean test(Integer integer) throws Exception {
if (integer == 4) {
return true;
}
return false;
}
})
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(Integer o) {
Log("Observer:onNext-" + o);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
2019-11-29 16:44:03 x999x:Observer: onSubscribe
2019-11-29 16:44:03 x999x:Observer:onNext-4
2019-11-29 16:44:03 x999x:Observer:onComplete
-
distinct
去掉重复数据。
Observable.fromArray(1,2, 3, 3, 4, 1, 5)
.distinct()
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(Integer o) {
Log("Observer:onNext-" + o);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
2019-12-02 09:19:11 x999x:Observer: onSubscribe
2019-12-02 09:19:11 x999x:Observer:onNext-1
2019-12-02 09:19:11 x999x:Observer:onNext-2
2019-12-02 09:19:11 x999x:Observer:onNext-3
2019-12-02 09:19:11 x999x:Observer:onNext-4
2019-12-02 09:19:11 x999x:Observer:onNext-5
2019-12-02 09:19:11 x999x:Observer:onComplete
这个效果也很明显;
它还有两个扩展:
public final <K> Observable<T> distinct(Function<? super T, K> keySelector)
public final <K> Observable<T> distinct(Function<? super T, K> keySelector, Callable<? extends Collection<? super K>> collectionSupplier)
* keySelector:生成Key的方法。将一个数据转换成一个Key,这Key用来确定一个数据是否和另一个数据不同。
* collectionSupplier: 生一个存放Key容器。每次有数据到来时,都会调用容器的add方法将数据的Key值加入容器中,根据add方法的返回值来判断是否数据的表示唯一性,即add返回true(添加成功,数据唯一,发射到观察者),add返回false(添加失败,数据不唯一,不发射到观察者)
举例例子:
//测试对象
class TestDistinctC {
int i;
String s;
public TestDistinctC(int i, String s) {
this.i = i;
this.s = s;
}
@Override
public String toString() {
return "TestDistinctC{" +
"i=" + i +
", s='" + s + '\'' +
'}';
}
}
Observable.fromArray(new TestDistinctC(1, "1"),
new TestDistinctC(2, "1"),
new TestDistinctC(3, "1"),
new TestDistinctC(2, "1"),
new TestDistinctC(3, "1"),
new TestDistinctC(1, "1"),
new TestDistinctC(5, "1"))
.distinct(new Function<TestDistinctC, String>() {
@Override
public String apply(TestDistinctC testDistinctC) throws Exception {
Log("apply-" + testDistinctC);
return testDistinctC.toString();
}
}, new Callable<Collection<? super Object>>() {
@Override
public Collection<? super Object> call() throws Exception {
Log("Collection-call");
return new HashSet<>();
}
})
.subscribe(new Observer<TestDistinctC>() {
@Override
public void onSubscribe(Disposable d) {
Log("Observer: onSubscribe");
}
@Override
public void onNext(TestDistinctC o) {
Log("Observer:onNext-" + o);
}
@Override
public void onError(Throwable e) {
Log("Observer:onError");
}
@Override
public void onComplete() {
Log("Observer:onComplete");
}
});
2019-12-02 09:54:03 x999x:Collection-call
2019-12-02 09:54:03 x999x:Observer: onSubscribe
2019-12-02 09:54:03 x999x:apply-TestDistinctC{i=1, s='1'}
2019-12-02 09:54:03 x999x:Observer:onNext-TestDistinctC{i=1, s='1'}
2019-12-02 09:54:03 x999x:apply-TestDistinctC{i=2, s='1'}
2019-12-02 09:54:03 x999x:Observer:onNext-TestDistinctC{i=2, s='1'}
2019-12-02 09:54:03 x999x:apply-TestDistinctC{i=3, s='1'}
2019-12-02 09:54:03 x999x:Observer:onNext-TestDistinctC{i=3, s='1'}
2019-12-02 09:54:03 x999x:apply-TestDistinctC{i=2, s='1'}
2019-12-02 09:54:03 x999x:apply-TestDistinctC{i=3, s='1'}
2019-12-02 09:54:03 x999x:apply-TestDistinctC{i=1, s='1'}
2019-12-02 09:54:03 x999x:apply-TestDistinctC{i=5, s='1'}
2019-12-02 09:54:03 x999x:Observer:onNext-TestDistinctC{i=5, s='1'}
2019-12-02 09:54:03 x999x:Observer:onComplete
这里的Key是对象的toString方法;
容器是HashSet;
补充下HashSet的add方法返回的规则:
@return <tt>true</tt> if this set did not already contain the specified
有兴趣的同学可以试一下把HashSet换成ArrayList;
-
flatMap
把一个发射器Observable通过某种方法转换为多个Observables,然后再把这些分散的Observables装进一个单一的发射器Observable。但有个需要注意的是,flatMap 并不能保证事件的顺序。
class TestFlatMapOrigin{
int i;
int j;
int k;
public TestFlatMapOrigin(int i, int j, int k) {
this.i = i;
this.j = j;
this.k = k;
}
@Override
public String toString() {
return "TestFlatMapOrigin{" +
"i=" + i +
", j=" + j +
", k=" + k +
'}';
}
}
class TestFlatMap{
int i;
public TestFlatMap(int i) {
this.i = i;
}
@Override
public String toString() {
return "TestFlatMap{" +
"i=" + i +
'}';
}
}
Observable.fromArray(new TestFlatMapOrigin(1,2, 3),
new TestFlatMapOrigin(4,5, 6))
.flatMap(new Function<TestFlatMapOrigin, ObservableSource<TestFlatMap>>() {
@Override
public ObservableSource<TestFlatMap> apply(TestFlatMapOrigin origin) throws Exception {
ArrayList<TestFlatMap> list = new ArrayList<>();
list.add(new TestFlatMap(origin.i));
list.add(new TestFlatMap(origin.j));
list.add(new TestFlatMap(origin.k));
return Observable.fromIterable(list);
}
})
.subscribe(new Observer<TestFlatMap>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(TestFlatMap testFlatMap) {
Log("onNext: " + testFlatMap);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
2019-12-02 10:34:41 x999x:onSubscribe
2019-12-02 10:34:41 x999x:onNext: TestFlatMap{i=1}
2019-12-02 10:34:41 x999x:onNext: TestFlatMap{i=2}
2019-12-02 10:34:41 x999x:onNext: TestFlatMap{i=3}
2019-12-02 10:34:41 x999x:onNext: TestFlatMap{i=4}
2019-12-02 10:34:41 x999x:onNext: TestFlatMap{i=5}
2019-12-02 10:34:41 x999x:onNext: TestFlatMap{i=6}
2019-12-02 10:34:41 x999x:onComplete
使用起来还是挺方便的。还有很多扩展的参数可选,有时间再专门开一篇分析。
-
concatMap
concatMap与FlatMap的唯一区别就是concatMap保证了顺序。
-
debounce
去除发送频率过快的项,主要有两种判断模式:
public final Observable<T> debounce(long timeout, TimeUnit unit, Scheduler scheduler)
public final <U> Observable<T> debounce(Function<? super T, ? extends ObservableSource<U>> debounceSelector)
第一种是通过时间判断。timeout可以理解为发送间隔。发射完数据后,计时器会重置。
示例中,timeout为100毫秒。
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
Thread.sleep(10);
emitter.onNext(2);
Thread.sleep(50);
emitter.onNext(3);
Thread.sleep(60);
emitter.onNext(4);
Thread.sleep(160);
emitter.onNext(5);
emitter.onNext(6);
emitter.onComplete();
}
})
.debounce(100, TimeUnit.MILLISECONDS)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log("onNext-" + integer);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
2019-12-02 11:01:46 x999x:onSubscribe
2019-12-02 11:01:46 x999x:onNext-4
2019-12-02 11:01:46 x999x:onNext-6
2019-12-02 11:01:46 x999x:onComplete
可以看到,调用onComplete之后,不管onNext-6之后虽然没有给延迟,但依然将onNext-6发射出来了。
有兴趣的同学可以试下把onComplete拿掉。
-
last
仅取出可观察到的最后一个值,或者是满足某些条件的最后一项
Observable.fromArray(1,2 ,3)
.last(2)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log("accept: " + integer);
}
});
这里要注意的是观察者是Consumer。因为last返回的是Single<T>。参数2,是当无数据时的默认值。
2019-12-02 13:03:02 x999x:accept: 3
-
merge
把多个Observable结合起来,接受可变参数,也支持迭代器集合。它和concat的区别在于,不用等到 发射器 A 发送完所有的事件再进行发射器 B 的发送
Observable<Integer> o1 = Observable.fromArray(1, 2, 3, 4, 5, 6, 7);
Observable<Integer> o2 = Observable.fromArray(11, 12, 13, 14, 15, 16, 17);
Observable.merge(o1, o2)
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Integer integer) {
Log("onNext-" + integer);
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
2019-12-02 13:10:53 x999x:onSubscribe
2019-12-02 13:10:53 x999x:onNext-1
2019-12-02 13:10:53 x999x:onNext-2
2019-12-02 13:10:53 x999x:onNext-3
2019-12-02 13:10:53 x999x:onNext-4
2019-12-02 13:10:53 x999x:onNext-5
2019-12-02 13:10:53 x999x:onNext-6
2019-12-02 13:10:53 x999x:onNext-7
2019-12-02 13:10:53 x999x:onNext-11
2019-12-02 13:10:53 x999x:onNext-12
2019-12-02 13:10:53 x999x:onNext-13
2019-12-02 13:10:53 x999x:onNext-14
2019-12-02 13:10:53 x999x:onNext-15
2019-12-02 13:10:53 x999x:onNext-16
2019-12-02 13:10:53 x999x:onNext-17
2019-12-02 13:10:53 x999x:onComplete
从这个例子看,似乎和concat没啥区别。
-
reduce
每次用一个方法处理一个值,可以有一个 seed
作为初始值
Observable.fromArray(1,2,3)
.reduce(new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) throws Exception {
return integer + integer2;
}
})
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log("accept: " + integer);
}
});
2019-12-02 13:15:07 x999x:accept: 6
用作求和的之类操作挺好用,如果有需要预处理则先用map。
-
scan
操作符作用和上面的 reduce一致,唯一区别是 reduce只追求结果,而 scan会始终如一地把每一个步骤都输出。
Observable.fromArray(1,2,3)
.scan(new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer integer, Integer integer2) throws Exception {
return integer + integer2;
}
})
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log("accept: " + integer);
}
});
2019-12-02 13:20:56 x999x:accept: 1
2019-12-02 13:20:56 x999x:accept: 3
2019-12-02 13:20:56 x999x:accept: 6
-
window
按照实际划分窗口,将数据发送给不同的Observable
Observable.fromArray(1,2,3,11,22,33, 666, 778)
.window(3)
.subscribe(new Observer<Observable<Integer>>() {
@Override
public void onSubscribe(Disposable d) {
Log("onSubscribe");
}
@Override
public void onNext(Observable<Integer> observable) {
Log("onNext-" + observable);
observable.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log("accept-" + integer);
}
});
}
@Override
public void onError(Throwable e) {
Log("onError");
}
@Override
public void onComplete() {
Log("onComplete");
}
});
2019-12-02 13:25:00 x999x:onSubscribe
2019-12-02 13:25:00 x999x:onNext-io.reactivex.subjects.UnicastSubject@3e6fa38a
2019-12-02 13:25:00 x999x:accept-1
2019-12-02 13:25:00 x999x:accept-2
2019-12-02 13:25:00 x999x:accept-3
2019-12-02 13:25:00 x999x:onNext-io.reactivex.subjects.UnicastSubject@3abbfa04
2019-12-02 13:25:00 x999x:accept-11
2019-12-02 13:25:00 x999x:accept-22
2019-12-02 13:25:00 x999x:accept-33
2019-12-02 13:25:00 x999x:onNext-io.reactivex.subjects.UnicastSubject@57fffcd7
2019-12-02 13:25:00 x999x:accept-666
2019-12-02 13:25:00 x999x:accept-778
2019-12-02 13:25:00 x999x:onComplete
单看效果的话,类似之前的buffer。
不同点是,buffer切割成List,而window切割成Observable。
-
take
接受一个 long 型参数 count ,代表至多接收 count 个数据
Observable.fromArray(1,2 ,3 ,4)
.take(2)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log("accept: " + integer);
}
});
2019-12-02 13:28:40 x999x:accept: 1
2019-12-02 13:28:40 x999x:accept: 2
定时和延迟:
timer | 定时任务 |
interval | 用于间隔时间执行某个操作,其接受三个参数,分别是第一次发送延迟,间隔时间,时间单位 |
defer | 每次订阅都会创建一个新的Observable,并且如果没有被订阅,就不会产生新的Observable |
delay | 延迟 |
-
delay
延迟
Log.d("x999x", "test start");
Observable.just(1,2,3)
.delay(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d("x999x", "accept-" + integer);
}
});
2019-12-03 09:42:20.993 D/x999x: test start
2019-12-03 09:42:22.010 D/x999x: accept-1
2019-12-03 09:42:22.011 D/x999x: accept-2
2019-12-03 09:42:22.012 D/x999x: accept-3
作用在Observable上的一个延迟操作,示例已经很明显了;
中间有个比较扯蛋事情,原先是用test直接run的,但是和时间相关的在test里面run不了,所以不得不改成在具体项目中run了,有点慢。现在具体原因还不清楚,如果有懂的同学请知会一声,谢谢!
-
timer
定时任务
Log.d("x999x", "test start");
Observable.timer(1, TimeUnit.SECONDS)
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
Log.d("x999x", "accept" + aLong);
}
});
2019-12-03 09:49:43.567 D/x999x: test start
2019-12-03 09:49:44.577 D/x999x: accept0
-
interval
用于间隔时间执行某个操作,其接受三个参数,分别是第一次发送延迟,间隔时间,时间单位
Observable.interval(1, TimeUnit.SECONDS)
.take(3)
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
Log.d("x999x", "accept" + aLong);
}
});
2019-12-03 09:52:45.136 D/x999x: test start
2019-12-03 09:52:46.149 D/x999x: accept0
2019-12-03 09:52:47.148 D/x999x: accept1
2019-12-03 09:52:48.149 D/x999x: accept2
这里用了之前提到的take,只获取前面的三个数据。
如果想要手动停止则需要稍微修改一下例子:
// 1. 找一个合适的地方定义一个Disposable变量
Disposable disposable;
Observable.interval(1, TimeUnit.SECONDS)
.subscribe(new Observer<Long>() {
@Override
public void onSubscribe(Disposable d) {
// 2. 对Disposable变量赋值
disposable = d;
}
@Override
public void onNext(Long aLong) {
Log.d("x999x", "onNext-" + aLong);
}
@Override
public void onError(Throwable e) {
Log.d("x999x", "onError");
}
@Override
public void onComplete() {
Log.d("x999x", "onComplete");
}
});
// 3. 在你想要停止的时候,调用Disposable变量的dispose方法
disposable.dispose();
2019-12-03 09:58:43.185 D/x999x: test start
2019-12-03 09:58:44.194 D/x999x: onNext-0
2019-12-03 09:58:45.193 D/x999x: onNext-1
2019-12-03 09:58:46.194 D/x999x: onNext-2
2019-12-03 09:58:47.194 D/x999x: onNext-3
2019-12-03 09:58:48.195 D/x999x: onNext-4
2019-12-03 09:58:49.194 D/x999x: onNext-5
2019-12-03 09:58:50.195 D/x999x: onNext-6
2019-12-03 09:58:50.613 D/x999x: test end
Disposable在上面已经有过介绍,就不重复展开了;
timer也可以通过Disposable提前停止,涉及Activity的话,最好还是在onStop或者onDistory中停掉,不然会有内存泄漏;
-
defer
每次订阅都会创建一个新的Observable,并且如果没有被订阅,就不会产生新的Observable
Log.d("x999x", "test");
Observable<Integer> defer = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> call() throws Exception {
Log.d("x999x", "call");
return Observable.just(1);
}
});
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
defer.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d("x999x", "accept-" + integer);
}
});
2019-12-03 10:33:05.189 D/x999x: test
2019-12-03 10:33:15.198 D/x999x: call
2019-12-03 10:33:15.200 D/x999x: accept-1
专门搞了个延迟10s做测试。
背压式:
被观察者发送事件的速度大于观察者接收事件的速度时,观察者内会创建一个无限制大少的缓冲池存储未接收的事件,因此当存储的事件越来越多时就会导致OOM的出现
Flowable | 被观察者 |
Subscriber | 观察者 |
举个例子:
Flowable.create(new FlowableOnSubscribe<String>() {
@Override
public void subscribe(FlowableEmitter<String> emitter) throws Exception {
}
}, BackpressureStrategy.BUFFER)
.subscribe(new Subscriber<String>() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(String s) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
});
其它
Single/SingleObserver | Single只会接收一个参数,而SingleObserver只会调用onError()或者onSuccess() |
retry | 重试 |
retryUntil | 出现错误后,判断是否需要重新发送数据 |
retryWhen | 遇到错误时,将发生的错误传递给一个新的被观察者,并决定是否需要重新订阅原始被观察者 |
repeat | 重复发送 |
repeatWhen | 有条件地重复发送 |