目录
RxJava2 官方文档:http://reactivex.io/RxJava/2.x/javadoc/
注:RxJava 2.x 相对于 RxJava 1.x 变化较大,所以需要单独记录
RxJava2 官方文档:http://reactivex.io/RxJava/2.x/javadoc/
参考:https://www.jianshu.com/p/0cd258eecf60
实战知识梳理:https://www.jianshu.com/p/c935d0860186
依赖
只需要在buid.gradle中添加依赖:
compile 'io.reactivex.rxjava2:rxjava:2.1.1'
接口变化
RxJava 2.x 拥有了新的特性,其依赖与四个基础接口,它们分别是:
- - Publisher
- - Subscriber
- - Subscription
- - Processor
其中最核心的莫过于 Publisher 和 Subscriber。Publisher 可以发出一系列的事件,而 Subscriber 负责和处理这些事件。
其中用的比较多的自然是 Publisher的 Flowable, 它支持背压。关于背压给个简单的定义就是:
背压是指在异步场景中,被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略。
简而言之,背压是流速控制的一种策略。有兴趣的可以看下官方对背压的讲解.
可以明显发现,RxJava 2.x 最大的改动就是对于 backpressure 的处理,为此将原理的 Observable 拆分成新的 Observable 和 Flowable,同时其他相关部分也同时进行了拆分
观察者模式
RxJava 以观察者模式为骨架,在2.x 中依旧如此。不过现在出现了两种观察者模式:
- Observable(被观察者)/ Observer(观察者)
- Flowable(被观察者)/ Subscriber(观察者)
在RxJava 2.x 中,Observable 用于订阅 Observer ,不在支持背压(1.x 中可以使用背压策略),而 Flowable 用于订阅 Subscriber, 是支持背压(Backpressure)的。
Observable
在RxJava 1.x 中,我们最熟悉的就是 Observable 这个类了。用 RxJava 1.x 实现订阅:
第一步:初始化 Observable
第二步:初始化 Observer
第三步:建立订阅关系
使用RxJava 2.x 的 Observable 与 Observer 的步骤 与 1.x 差不多,直接上代码:
Observable.create(new ObservableOnSubscribe<Integer>(){ //第一步,初始化 Observable
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
Log.e(TAG, "Observable emit 1" + "\n");
e.onNext(1);
Log.e(TAG, "Observable emit 2" + "\n");
e.onNext(2);
Log.e(TAG, "Observable emit 3" + "\n");
e.onNext(3);
e.onComplete();
Log.e(TAG, "Observable emit 4" + "\n" );
e.onNext(4);
}
}).subscribe(new Observer<Integer>(){ //第三步 订阅
//第二步,初始化Obserber
private int i;
private Disposable mDisposable;
@Override
public void onSubscribe(@NonNull Disposable d){
mDisposable = d;
}
@Override
public void onNext(@NonNull Integer integer){
i++;
if(i==2){
//在RxJava 2.x中,新增的Disposable 可以做到切断的操作,
//让Observer观察者不在接受上游事件
mDiaposable.dispose();
}
}
@Override
public void onError(@NnoNull Throwable e){
Log.e(TAG, "onError : value : " + e.getMessage() + "\n" );
}
@Override
public void onComplete(){
Log.e(TAG, "onComplete" + "\n" );
}
});
不难看出,2.x 与 1.x 还是存在一些区别的。
首先,创建 Observable 时,回调的是 ObservableEmitter ,字面意思即 发射器,并且直接 Throws Exception。其次,在创建的 Observer 中,也多了一个回调方法: onSubscribe ,传递参数为 Diaposable, Disposable 相当于 RxJava 1.x 中的Subscription, 用于 接触订阅。从下图的输出结果可以看到,在i自增到2的时候,订阅关系被切断:
07-03 14:24:11.663 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: onSubscribe : false
07-03 14:24:11.664 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: Observable emit 1
07-03 14:24:11.665 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: onNext : value : 1
07-03 14:24:11.666 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: Observable emit 2
07-03 14:24:11.667 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: onNext : value : 2
07-03 14:24:11.668 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: onNext : isDisposable : true
07-03 14:24:11.669 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: Observable emit 3
07-03 14:24:11.670 18467-18467/com.nanchen.rxjava2examples E/RxCreateActivity: Observable emit 4
当然,我们的RxJava 2.x 也为我们保留了简化版订阅方式,我们可以根据需求,进行相应的简化订阅,只不过传入对象改为了 Consumer。
Consumer 即 消费者,用于接收单个值,BigConsumer 则是接收两个值,Function 用于 变换对象, Predicate 用于判断。这些接口命名大多参照了 java8 。
将上述例子用简化版的方式实现:
Observable.create(new ObservableOnSubscribe<Integer>(){ //第一步,初始化 Observable
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
Log.e(TAG, "Observable emit 1" + "\n");
e.onNext(1);
Log.e(TAG, "Observable emit 2" + "\n");
e.onNext(2);
Log.e(TAG, "Observable emit 3" + "\n");
e.onNext(3);
e.onComplete();
Log.e(TAG, "Observable emit 4" + "\n" );
e.onNext(4);
}
}).subscribe(new Consumer<Integer>(){
@Override
public void accept(Integer integer) throws Exception{
//这里接受数据项
}
},new Consumer<Throwable>(){
@Overrride
public void accept(Throwable throwable) throws Exception{
//这里接受 onError
Log.e(TAG, "onError : value : " + e.getMessage() + "\n" );
}
}, new Action(){
@Override
public void run() throws Exception{
//这里接受 onComplete
Log.e(TAG, "onComplete" + "\n" );
}
});
Map 操作符
map 基本算是 RxJava 中一个最简单的操作符了,它的作用是对发射时间发送的每一个时事件应用一个函数,每一个事件都按照指定的函数去变化
Observable.create(new ObservableOnSubscribe<Integer>(){
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
})
.map(new Function<Integer, String>(){
@Override
public String apply(@NonNull Integer integer) throws Exception{
// map 操作符,就是转换输入 ,输出类型:本例子中,输入时Integer,输出是String
return "this is result:"+integer;
}
})
.subscribeOn(Schedulers.io()) //在子线程中发射
.observeOn(AndroidSchedulers.mainThread()) //在主线程接收
.subscribe(new Comsume<String>(){
@Override
public void accept(@NonNull String s) throws Exception{
//处理返回出来的数据
}
})
;
flatMap 操作符
FlatMap 是一个很有趣的东西,会在实际开发中经常用到,它可以把一个发射器 Observable 通过某种方法转换为多个 Observables,然后再将这些分散的 Observables 装进一个单一的发射器 Observable。但有个需要注意的是:flatMap 并不能保存事件的顺序,如果需要保证,需要用到我们下面要讲的 ConcatMap
Observable.create(new ObservableOnSubscribe<Integer>(){
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception{
e.onNext(1):
e.onNext(2);
e.onNext(3);
}
})
.flatMap(new Function<Integer, ObservableSource<String>(){
@Override
public ObservableSource<String> apply(@NonNull Integer integer) throws Exception{
List<String> list = new ArrayList<>();
for(int i = 0;i<3;i++){
list.add("I am value"+integer);
}
//随机生成一个时间
int delayTime = (int)(1+Math.random() *10);
return Observable.fromIterable(list).delay(delayTime,TimeUnit.MILLISECONDS);s
}
})
.subscribe(new Comsumer<String>(){
@Override
public void accept(String s) throws Exceptioon{
Log.e("mylog","accept:"+s);
}
})
;
输出结果:
E/zhao: accept: I am value 1
E/zhao: accept: I am value 3
E/zhao: accept: I am value 3
E/zhao: accept: I am value 3
E/zhao: accept: I am value 1
E/zhao: accept: I am value 1
E/zhao: accept: I am value 2
E/zhao: accept: I am value 2
E/zhao: accept: I am value 2
可以看到,输出结果是无顺序得。
concatMap 操作符
comcatMap 与 FlatMap 的唯一区别就是 concatMap 保证了顺序,所以我们就直接把flatMap 替换为 concatMap
输出结果:
E/zhao: accept: I am value 1
E/zhao: accept: I am value 1
E/zhao: accept: I am value 1
E/zhao: accept: I am value 2
E/zhao: accept: I am value 2
E/zhao: accept: I am value 2
E/zhao: accept: I am value 3
E/zhao: accept: I am value 3
E/zhao: accept: I am value 3
输出结果是有序的。
ZIP 操作符
构建一个String 发射器 和 Integer 发射器
// 创建String 发射器
private Observable<String> getStringObservable(){
return Observable.create(new ObservableOnSubscribe<String>(){
@Override
public void subscribe(@NonNull ObservableEmitter<String> e) throws Exception{
e.onNext("A");
e.onNext("B"):
e.onNext("C"):
}
}
}
//创建 Integer 发射器
private Observable<Integer> getIntegerObservable(){
return Observable.create(new ObservableOnSubscribe<Integer>(){
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception{
e.onNext(1):
e.onNext(2):
}
}
}
使用 zip操作符:
Observable.zip(getStringObservable(), getIntegerObservable(), new BiFunction<String, Integer,String>(){
@Override
public void apply(@NonNull String s,@NonNull Integer integer) throws Exception{
return s+integer;
}
})
.subscribe(new Comsumer<String>(){
@Override
public void accept(String s ) throws Exception{
Log.e("mylog","accept:"+s):
}
});
执行结果:
E/zhao: accept: A1
E/zhao: accept: B2
E/zhao: accept: C3
需要注意的是:
1)zip组合事件的过程 就是分别把 发射器A 和 发射器B 各取出一个事件来组合,并且一个事件只能被使用一次,组合的顺序 是严格按照事件发送的顺序来进行的,所以上面代码执行结果中,可以看到,1 永远是和A结合的,2永远是和B结合的
2)最终接收器收到的事件数量是和发送器发送事件最少的那个发送器的发送事件数量相同
interval 操作符
interval操作符是每隔一段时间就产生一个数字,这些数字从0开始,一次递增1 直至无穷大
方法1:
Flowable.interval(1,TimeUti.SECONDS)
.subscribe(new Comsumer<Long>(){
@Override
public void accept(@NonNull Long long) throws Exception{
Log.e("mylog","accept:"+long);
}
});
方法2:
Observable.interval(1,TimeUtil.SECONDS)
.subscribe(new Comsumer<Long>(){
@Override
public void accept(Long long) throws Exception{
Log.e("mylog","accept:"+long);
}
});
倒计时
既然interval 操作符会产生从0无穷大的序列,那么我们可以反过来思考,就会发现可以用interval方法,实现一个倒计时功能
创建一个倒计时的Observable
public void Observable<Long> countdown(final long time){
return Observable.interval(1, TimeUtil.SECONDS)
.map(new Function<Long, Long>(){
@Override
public long apply(@NonNull Long long) throws Exception{
return time-long;
}
}).take(time+1);
}
实现倒计时的功能:
countdown(4).subscribe(new Consumer<Long>(){
@Override
public void accept(Long long) throws Exception{
Log.e("mylog","accept:"+long);
}
}
执行结果输出:
E/mylog: accept: 倒计时: 4
E/mylog: accept: 倒计时: 3
E/mylog: accept: 倒计时: 2
E/mylog: accept: 倒计时: 1
E/mylog: accept: 倒计时: 0
repeat 操作符:重复的发射数据
repeat 重复地发射数据
- repeat() //无限重复
- repeat(int time) //设定重复的次数
Observable
.just(1,2)
.repeat(3) //重复3次
.subscribe(new Comsumer<Integer>(){
@Override
public void accept(Integer integer) throws Exception{
Log.e("mylog","accept:"+integer);
}
});
输出结果:
E/mylog: accept: 1
E/mylog: accept: 2
E/mylog: accept: 1
E/mylog: accept: 2
E/mylog: accept: 1
E/mylog: accept: 2
range:发射特定的整数序列
range 发射特定的整数序列的 Observable
要求, end >= start
Observable
.range(1,5)
.subscribe(new Comsumer<Integer>(){
@Override
public void accept(Integer integer) throws Exception{
Log.e("mylog","accept:"+integer):
}
});
输出结果:
E/mylog: accept: 1
E/mylog: accept: 2
E/mylog: accept: 3
E/mylog: accept: 4
E/mylog: accept: 5
fromArray:遍历数组
Integer[] items = {0,1,2,3,4,5};
Observable
.fromArray(items)
.subscribe(new Comsumer<Integer>(){
@Override
public void accept(Integer integer) throws Exception{
Log.e("mylog","accept:"+integer);
}
});
输出结果:
E/mylog: accept: 0
E/mylog: accept: 1
E/mylog: accept: 2
E/mylog: accept: 3
E/mylog: accept: 4
E/mylog: accept: 5
fromIterable:遍历集合
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c"):
Observable
.fromIterable(list)
.subscribe(new Comsumber<String>(){
@Override
public void accept(String s) throws Exception{
Log.e("mylog","accept:"+s);
}
});
输出结果:
E/mylog: accept: a
E/mylog: accept: b
E/mylog: accept: c
toList:把数据转换成list集合
Observable
.just(1,2,3,4)
.toList()
.subscribe(new Comsumer<List<Integer>>(){
@Override
public void accept(List<Integer> integers) thorows Exception{
Log.e("mylog","accept:"+integers);
}
});
输出结果:
accept: [1, 2, 3, 4]
把数组转换成list集合
Integer[] items = {0, 1, 2, 3, 4, 5};
Observable
.fromArray( items ) //遍历数组
.toList() //把遍历后的数组转化成 List
.subscribe(new Consumer<List<Integer>>() {
@Override
public void accept(List<Integer> integers) throws Exception {
Log.e("zhao", "accept: " + integers);
}
});
输出结果:
accept: [0, 1, 2, 3, 4, 5]
delay:延迟发射数据
Observable
.just(1, 2, 3)
.delay(3, TimeUnit.SECONDS) //延迟3秒钟,然后在发射数据
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.e("zhao", "accept: " + integer);
}
});
背压 BackPressure
背压产生的原因:被观察者发送信息太快以至于它的操作符或者订阅者不能及时处理相关的信息。在 RxJava 1.x 版本很容易就会报错,是程序发生奔溃:
...
Caused by: rx.exceptions.MissingBackpressureException
...
...
为了解决这个问题,在RxJava2 里面,引入了 Flowable 类:Observable 不包含 backpressure 处理,而 Flowable 包含。
模拟背压
我们来模拟一个 触发背压的实例,发射器每一毫秒 发射一个数据,接收器每一秒处理一个数据。数据产生是数据处理的1000倍。
首先用 RxJava 2.x 版本的 Observable 来实现
Observable.interval(1,TimeUtil.MILLISECONDS)
.subscribeOn(Schedulers.io()) //发射数据
.observeOn(Schedulers.newThread()) //接收数据
.subscribe(new Comsumer<Long>(){
@Override
public void accept(Long long) throws Exception{
Thread.sleep(1000);
Log.e("mylog","onNext:"+long);
}
});
经过测试,APP 很健壮,没有发生崩溃,日志每一秒打印一次。在上面我们说 2.x 版本中 Observable 不再支持背压,发射器生成的数据全部缓存到内存中
Observable:
- 不支持backpressure 处理,不会发生 MissingBackpressureException 异常
- 所有没有处理的数据缓存到内存中,等待被订阅者处理
- 坏处是:当产生数据过快,内存中缓存的数据越来越多,占用大量内存
然后用 RxJava 2.x 版本的Flowable 来实现:
Flowable.interval(1, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
Thread.sleep(1000);
Log.e("zhao", "onNext: " + aLong);
}
});
运行时,发生程序奔溃:
io.reactivex.exceptions.OnErrorNotImplementedException: Can't deliver value 128 due to lack of requests
...
...
Caused by: io.reactivex.exceptions.MissingBackpressureException: Can't deliver value 128 due to lack of requests
很明显发生了 MisssingBackpressureException 异常,128 代表是Flowable 最多缓存128 个数据,缓存超过128个数据,就会报错。
但是 RxJava 2.x 给我们提供le背压策略
onBackpressureDrop
onBackpressureDrop():当缓存区数据满 128 个时,在进来新的数据就会被丢弃,如果此时有数据被消费了,那么就会把当前最新产生的数据放到缓存区中。简单来说 就是把存不下来的数据丢弃。
测试:
Flowable.interval( 1 , TimeUnit.MILLISECONDS)
.onBackpressureDrop() //onBackpressureDrop 一定要放在 interval 后面否则不会生效
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
Thread.sleep(1000);
Log.e("zhao", "onNext: " + aLong);
}
});
打印结果:
E/zhao: onNext: 0
E/zhao: onNext: 1
...
E/zhao: onNext: 126
E/zhao: onNext: 127
E/zhao: onNext: 96129
E/zhao: onNext: 96130
E/zhao: onNext: 96131
从结果看,1到 127 总共 128个数据是连续的,下一个数据就是 96129了,128-96128的数据丢失了
注意事项 :onBackpressureDrop 一定要放在 interval 后面 否则不会生效
onBackpressureLatest
onBackpressureLatest 只保留最新的事件
onBackpressureBuffer
onBackpressureBuffer:默认情况下缓存所有的数据,不会丢失数据,这个方法可以解决背压问题,但是它和Observable一样有全缺点,缓存数据太多,占用太多内存
onBackpressureBuffer(int capacity):设置缓存大小,但是如果缓存数据超过这个值,就会奔溃
注意:onBackpressureBuffer 一定要放在 interval 后面否则让不会生效
参考:https://blog.youkuaiyun.com/zhaoyanjun6/article/details/76443347