https://www.jianshu.com/p/bb58571cdb64 该系列文章学习笔记,转化成自己的话,以后看起来比较容易懂。
引入:
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
上游发送事件,由下游接收,发送事件的是被观察者,而接收的是观察者,中间二者的连接就是subscribe() ,转化成代码就是
//被观察者 发送事件
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
Log.i("发送事件", "subscribe: 1");
e.onNext("========11111");
Log.i("发送事件", "subscribe: 2");
e.onNext("========22222");
Log.i("发送事件", "subscribe: 3");
e.onNext("========33333");
Log.i("发送事件", "subscribe: 4");
e.onNext("========44444");
e.onComplete();
}
}).subscribe(new Observer() {
//将上游下游连接起来 并且添加一个观察者,接收事件。
@Override
public void onSubscribe(Disposable d) {
Log.d("订阅", "onSubscribe: ");
}
@Override
public void onNext(String value) {
Log.d("执行", "onNext: "+value);
}
@Override
public void onError(Throwable e) {
Log.d("错误", "onError: ");
}
@Override
public void onComplete() {
Log.d("完成", "onComplete: ");
}
});
}
打印结果是:
可以看到的是:首先是订阅,只有订阅了之后才会开始发送事件,而且发送事件是以队列的形式发送的,发送一个执行一个。
ObservableEmitter: Emitter是发射器的意思,这个就是用来发出事件的,它可以发出三种类型的事件,通过调用emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分别发出next事件、complete事件和error事件。
但是,请注意,并不意味着你可以随意乱七八糟发射事件,需要满足一定的规则:
上游可以发送无限个onNext, 下游也可以接收无限个onNext.
当上游发送了一个onComplete后, 上游onComplete之后的事件将会继续发送, 而下游收到onComplete事件之后将不再继续接收事件.
当上游发送了一个onError后, 上游onError之后的事件将继续发送, 而下游收到onError事件之后将不再继续接收事件.
上游可以不发送onComplete或onError.
最为关键的是onComplete和onError必须唯一并且互斥, 即不能发多个onComplete, 也不能发多个onError, 也不能先发一个onComplete, 然后再发一个onError, 反之亦然
注: 关于onComplete和onError唯一并且互斥这一点, 是需要自行在代码中进行控制, 如果你的代码逻辑中违背了这个规则, **并不一定会导致程序崩溃. ** 比如发送多个onComplete是可以正常运行的, 依然是收到第一个onComplete就不再接收了, 但若是发送多个onError, 则收到第二个onError事件会导致程序会崩溃.
如果上游发送了一个onComplete(),效果是怎么样的呢?
//被观察者 发送事件
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
Log.i("发送事件", "subscribe: 1");
e.onNext("========11111");
Log.i("发送事件", "subscribe: 2");
e.onNext("========22222");
Log.i("发送事件", "subscribe: 3");
e.onNext("========33333");
e.onComplete();//发送一个onComplete
Log.i("发送事件", "subscribe: 4");
e.onNext("========44444");
e.onComplete();
}
}).subscribe(new Observer() {
//将上游下游连接起来 并且添加一个观察者,接收事件。
@Override
public void onSubscribe(Disposable d) {
Log.d("订阅", "onSubscribe: ");
}
@Override
public void onNext(String value) {
Log.d("执行", "onNext: "+value);
}
@Override
public void onError(Throwable e) {
Log.d("错误", "onError: ");
}
@Override
public void onComplete() {
Log.d("完成", "onComplete: ");
}
});
打印结果:
可以看到发送onComplete之后,只有发送事件,没有接收事件,因此印证了上面说的事件会继续发送但不会接收。发送onError也一样。
这个单词的字面意思是一次性用品,用完即可丢弃的. 那么在RxJava中怎么去理解它呢, 对应于上面的水管的例子, 我们可以把它理解成两根管道之间的一个机关, 当调用它的dispose()方法时, 它就会将两根管道切断, 从而导致下游收不到事件.
//被观察者 发送事件
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
Log.i("发送事件", "subscribe: 1");
e.onNext("========11111");
Log.i("发送事件", "subscribe: 2");
e.onNext("========22222");
Log.i("发送事件", "subscribe: 3");
e.onNext("========33333");
Log.i("发送事件", "subscribe: 4");
e.onNext("========44444");
e.onComplete();
}
}).subscribe(new Observer() {
//将上游下游连接起来 并且添加一个观察者,接收事件。
private Disposable disposable;
private int I;
@Override
public void onSubscribe(Disposable d) {
Log.d("订阅", "onSubscribe: ");
disposable = d;
}
@Override
public void onNext(String value) {
Log.d("执行", "onNext: "+value);
I++;
if(i == 2){
disposable.dispose();
Log.i("是否切断", "onNext: "+disposable.isDisposed());
}
}
@Override
public void onError(Throwable e) {
Log.d("错误", "onError: ");
}
@Override
public void onComplete() {
Log.d("完成", "onComplete: ");
}
});
如上代码所示,在i==2时,调用了disposable.dispose();切断了管道,那么下游就接收不到事件,打印出来如下:
可以看到,事件一直在发送,但是下游并没有继续接收了。
另外, subscribe()有多个重载的方法:
public final Disposable subscribe() {}
public final Disposable subscribe(Consumer super T> onNext) {}
public final Disposable subscribe(Consumer super T> onNext, Consumer super Throwable> onError) {}
public final Disposable subscribe(Consumer super T> onNext, Consumer super Throwable> onError, Action onComplete) {}
public final Disposable subscribe(Consumer super T> onNext, Consumer super Throwable> onError, Action onComplete, Consumer super Disposable> onSubscribe) {}
public final void subscribe(Observer super T> observer) {}
不带任何参数的subscribe() :表示下游不关心任何事件,你上游尽管发你的数据去吧, 老子可不管你发什么.
带有一个Consumer参数的方法表示下游只关心onNext事件, 其他的事件我假装没看见, 因此我们如果只需要onNext事件可以这么写:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
Log.d(TAG, "emit 1");
emitter.onNext(1);
Log.d(TAG, "emit 2");
emitter.onNext(2);
Log.d(TAG, "emit 3");
emitter.onNext(3);
Log.d(TAG, "emit complete");
emitter.onComplete();
Log.d(TAG, "emit 4");
emitter.onNext(4);
}
}).subscribe(new Consumer() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "onNext: " + integer);
}
});
关键方法:subscribeOn() 指定的是上游发送事件的线程, observeOn() 指定的是下游接收事件的线程.
在RxJava中, 已经内置了很多线程选项供我们选择, 例如有
Schedulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作
Schedulers.computation() 代表CPU计算密集型的操作, 例如需要大量计算的操作
Schedulers.newThread() 代表一个常规的新线程
AndroidSchedulers.mainThread() 代表Android的主线程
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
//上游发送事件
Log.i("上游所在的线程", "subscribe: "+Thread.currentThread().getName());
Log.i("上游发送事件", "subscribe: ");
e.onNext("========1");
}
}).subscribeOn(Schedulers.newThread())//上游发送事件所在线程
.observeOn(AndroidSchedulers.mainThread())//下游接收事件所在线程
.subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.i("下游所在的线程", "accept: "+Thread.currentThread().getName());
Log.i("下游接收事件",s+"");
}
});
无论是做网络请求,还是做本地数据库的增删改查等,都是在上游,上游在子线程进行网络请求之后,发送消息给下游,下游在主线程接收消息,进行界面的更改等操作。
Map操作符 变化操作符,其作用就是对上游发送的每一个事件应用一个函数, 使得每一个事件都按照指定的函数去变化.
图中map中的函数作用是将圆形事件转换为矩形事件, 从而导致下游接收到的事件就变为了矩形.用代码来表示这个例子就是:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext(1);
}
}).map(new Function() {
@Override
public String apply(Integer integer) throws Exception {
Log.i("apply", "apply: "+integer);
return integer+"";
}
}).subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.i("accept", "accept: "+s);
}
});
打印出的结果就是:
可以看到,下游接收的s就是apply()的返回值。也就是在apply中可以手动转化数据类型,再发送给下游。
上游每发送一个事件, flatMap都将创建一个新的水管, 然后发送转换之后的新的事件, 下游接收到的就是这些新的水管发送的数据. 这里需要注意的是, flatMap并不保证事件的顺序, 也就是图中所看到的, 并不是事件1就在事件2的前面. 如果需要保证顺序则需要使用concatMap.
zip关键字是将上游两根管道里发送的数据结合起来,由下游接收。上游两根管道需要在两个不同的线程进行消息的发送。
组合的过程是分别从 两根水管里各取出一个事件 来进行组合, 并且一个事件只能被使用一次, 组合的顺序是严格按照事件发送的顺利 来进行的, 也就是说不会出现圆形1 事件和三角形B 事件进行合并, 也不可能出现圆形2 和三角形A 进行合并的情况.
最终下游收到的事件数量 是和上游中发送事件最少的那一根水管的事件数量 相同. 这个也很好理解, 因为是从每一根水管 里取一个事件来进行合并, 最少的 那个肯定就最先取完 , 这个时候其他的水管尽管还有事件 , 但是已经没有足够的事件来组合了, 因此下游就不会收到剩余的事件了.
Observable observable1 = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("1");
e.onNext("2");
e.onNext("3");
e.onNext("4");
e.onComplete();
}
}).subscribeOn(Schedulers.io());
Observable observable2 = Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
e.onNext("A");
e.onNext("B");
e.onNext("C");
e.onComplete();
}
}).subscribeOn(Schedulers.io());
Observable.zip(observable1, observable2, new BiFunction() {
@Override
public String apply(String s, String s2) throws Exception {
return s + s2;
}
}).subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
Log.i("订阅", "onSubscribe: ");
}
@Override
public void onNext(String value) {
Log.i("接收", "onNext: "+value);
}
@Override
public void onError(Throwable e) {
Log.i("错误", "onError: ");
}
@Override
public void onComplete() {
Log.i("完成", "onComplete: ");
}
});
打印出:
如果其中一个水管A发送事件特别快, 而另一个水管B 发送事件特别慢, 那就可能出现这种情况, 发得快的水管A 已经发送了1000个事件了, 而发的慢的水管B 才发一个出来, 组合了一个之后水管A 还剩999个事件, 这些事件需要继续等待水管B 发送事件出来组合, 那么这么多的事件是放在哪里的呢? 总有一个地方保存吧? 没错, Zip给我们的每一根水管都弄了一个水缸 , 用来保存这些事件, 用通俗易懂的图片来表示就是:
水缸并不是没有容量的,如果一直发送事件,会导致水缸爆掉,也就是造成OOM异常。那么怎么解决这个问题呢,第一、控制数量,第二、控制速度。
控制数量:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
for (int i = 0;;i++){
e.onNext(i+"");
}
}
}).subscribeOn(Schedulers.io())
.filter(new Predicate() {
@Override
public boolean test(String s) throws Exception {
return (s.equals("0") || s.equals("10"));
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(String s) throws Exception {
Log.d("接收事件", "accept: "+s);
}
});
但是这种情况下,会丢失数据。
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
for (int i = 0;;i++){
e.onNext(i);
}
}
}).subscribeOn(Schedulers.io())
.sample(2, TimeUnit.SECONDS)//每隔两秒取一个事件放入水缸
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Integer s) throws Exception {
Log.d("接收事件", "accept: "+s);
}
});
减慢发送速度:
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter e) throws Exception {
for (int i = 0;;i++){
e.onNext(i);
Thread.sleep(2000);//每次发送完睡两秒
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Integer s) throws Exception {
Log.d("接收事件", "accept: "+s);
}
});
使用flowable关键字时,需要添加两句代码,BackpressureStrategy.ERROR 和 s.request(Long.MAX_VALUE);第一句代码是添加背压,第二句代码是从上游的水缸中取出多少个交给下游。BackpressureStrategy.ERROR会在出现上下游流速不均衡的时候直接抛出一个异常,这个异常就是著名的MissingBackpressureException。request可以看成是下游处理事件的能力,上游根据下游能处理多少个事件来发送多少个事件。 如果下游没有调用request,那么上游会认为下游没有执行能力,会报MissingBackpressureException
在Flowable里默认有一个大小为128的水缸, 当上下游工作在不同的线程中时, 上游就会先把事件发送到这个水缸中, 因此, 下游虽然没有调用request, 但是上游在水缸中保存着这些事件, 只有当下游调用request时, 才从水缸里取出事件发给下游.
代码如下:
Flowable.create(new FlowableOnSubscribe() {
@Override
public void subscribe(FlowableEmitter e) throws Exception {
e.onNext(1);
Log.i("发送", "onNext: "+1);
e.onNext(2);
Log.i("发送", "onNext: "+2);
e.onNext(3);
Log.i("发送", "onNext: "+3);
e.onNext(4);
Log.i("发送", "onNext: "+4);
e.onComplete();
}
}, BackpressureStrategy.ERROR)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber() {
@Override
public void onSubscribe(Subscription s) {
Log.i("订阅", "onSubscribe: ");
// s.request(Long.MAX_VALUE);
s.request(2);
}
@Override
public void onNext(Integer integer) {
Log.i("接收", "onNext: "+integer);
}
@Override
public void onError(Throwable t) {
Log.i("错误", "onError: "+t);
}
@Override
public void onComplete() {
Log.i("完成", "onComplete: ");
}
});
运行结果:
我们看到上游发送了4个事件,但下游只接收了2个事件。