一、基本概念
1、定义
RxJava在GitHub上《RxJava》的自我介绍是:a library for composing asynchronous and event-based programs using observable sequences for the Java VM.(一个在Java VM 上使用可观测的序列来组成异步的,基于事件的程序的库),有些人可能感到疑惑,其实本质上可以用一词来概括——“异步”,它就是一个异步的操作库,而别的定语都基于这之上。
2、优点
简洁
异步操作很关键的一点是简洁性,因为在调度过程比较复杂的情况下,异步代码既难写也难读懂。Android创造的Handler和AsyncTask其实都是为了让异步代码更加简洁,RxJava的优势也是简洁,它的特别之处是:随着程序代码逻辑的变得越来越复杂,它依然保持简洁。
响应式编程
它是一种基于异步数据流概念的编程模式。数据流就像一条河:它可以被观测,被过滤,被操作,或者为新的消费者与另外一条流合并为一条新的流。
响应式编程的一个关键概念是事件。事件可以被等待,可以触发过程,也可以触发其它事件。事件是唯一的以合适的方式将我们的现实世界映射到我们的软件中:如果屋里太热了我们就打开一扇窗户。同样的,当我们的天气app从服务端获取到新的天气数据后,我们需要更新app上展示天气信息的UI;汽车上的车道偏移系统探测到车辆偏移了正常路线就会提醒驾驶者纠正,就是是响应事件。
今天,响应式编程最通用的一个场景是UI:我们的移动App必须做出对网络调用、用户触摸输入和系统弹框的响应。在这个世界上,软件之所以是事件驱动并响应的是因为现实生活也是如此。
二、基本使用
1、观察者模式
观察者模式面向的需求是:A对象(观察者)对B对象(被观察者)的某种变化高度敏感,需要在B对象变化的一瞬间做出变化。程序的观察者模式,观察者不需要时刻盯着被观察者,而是采用注册(Regsiter)或者订阅(Subscribe)的方式,告诉被观察者,我是你的某种状态,你的状态在发生变化的时候来通知我。
- Observable ( 被观察者 ) / Observer ( 观察者 )
-
Flowable (被观察者)/ Subscriber (观察者)
2、背压
背压是指在异步场景中,被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略。简而言之,背压是流速控制的一种策略。
由于基于FLowable发射的数据流,以及对数据加工处理的各种操作符都添加的背压支持,附加额外的逻辑,其运行效率要比Observable慢的多。
大数据流用Flowable,小数据流用Observable
51 回复
3、三部曲
- 第一步:初始化 Observable //观察者,它决定事件发生时有怎么样的行为;
- 第二步:初始化 Observer // 被观察者,它决定什么时候出发事件以及触发什么样的事件;
- 第三步:建立订阅关系subscribe() //订阅,将Observer和Observable关联起来。
//1、创建被观察者Observable
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("1");
e.onNext("2");
e.onNext("3");
e.onComplete();
}
});
//2、创建观察者Observer
Observer<String> observer = new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
//事件订阅成功回调,返回Disposable请求实例,可以通过d.dispose()取消请求;
System.out.println("onSubscribe: 订阅");
}
@Override
public void onNext(String s) {
//响应事件的方法,接收事件数据;
System.out.println("onNext: " + s);
}
@Override
public void onError(Throwable e) {
//事件队列异常,不再接收新的事件
System.out.println("onError: " + e.getMessage());
}
@Override
public void onComplete() {
//事件队列完结,不再接收新的事件
System.out.println("onComplete");
}
};
//3、订阅(观察者观察被观察者)
observable.subscribe(observer);
基本原理
先假设有两根水管:
上面一根水管为事件产生的水管,叫它上游(
被观察者Observable)
,下面一根水管为事件接收的水管叫它下游(
观察者Observer)
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事件会导致程序会崩溃.
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
System.out.println("subscribe: onNext=1");
e.onNext("1");
System.out.println("subscribe: onNext=2");
e.onNext("2");
System.out.println("subscribe: onComplete");
e.onComplete();
System.out.println("subscribe: onComplete");
e.onComplete();
System.out.println("subscribe: onError");
e.onError(new Throwable("Error"));
System.out.println("subscribe: onNext=3");
e.onNext("3");
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
System.out.println("onSubscribe: 订阅");
}
@Override
public void onNext(@NonNull String s) {
System.out.println("onNext: " + s);
}
@Override
public void onError(@NonNull Throwable e) {
System.out.println("onError: " + e.getMessage());
}
@Override
public void onComplete() {
System.out.println("onComplete()");
}
});
Disposable
这个单词的字面意思是一次性用品,用完即可丢弃的. 那么在RxJava中怎么去理解它呢, 对应于上面的水管的例子, 我们可以把它理解成两根管道之间的一个机关, 当调用它的dispose()
方法时, 它就会将两根管道切断, 从而导致下游收不到事件.
注意: 调用dispose()并不会导致上游不再继续发送事件, 上游会继续发送剩余的事件.
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
System.out.println("subscribe: onNext=1");
e.onNext("1");
System.out.println("subscribe: onNext=2");
e.onNext("2");
System.out.println("subscribe: onComplete");
e.onComplete();
System.out.println("subscribe: onNext=3");
e.onNext("3");
}
}).subscribe(new Observer<String>() {
private Disposable disposable;
@Override
public void onSubscribe(@NonNull Disposable d) {
System.out.println("onSubscribe: 订阅");
disposable = d;
}
@Override
public void onNext(@NonNull String s) {
System.out.println("onNext: " + s);
if ("2".equals(s)) {
System.out.println("disposable");
disposable.dispose();
System.out.println("isDisposed = " + disposable.isDisposed());
}
}
@Override
public void onError(@NonNull Throwable e) {
System.out.println("onError: " + e.getMessage());
}
@Override
public void onComplete() {
System.out.println("onComplete()");
}
});
订阅 subscribe()
连接Observable(被观察者)和Observer(观察者)。
Observable是被观察者,observer是观察者,创建完Observer和Observable之后,通过subscribe()将两者关联起来。
通过该调用,回调观察者的相关方法,从而响应被观察者响应的事件,Observable只生产事件,真正发送事件的是在它订阅的时候,即subscribe()被调用的时候。
另外:观察者Obaserver的subscribe具有多个重载的方法:
//观察者不对被观察者发送的事件做出响应(但是被观察者还可以继续发送事件)
public final Disposable subscribe()
//观察者对被观察者发送的任何事件都做出响应
public final void subscribe(Observer<? super T> observer)
//表示观察者只对被观察者发送的Next事件做出响应
public final Disposable subscribe(Consumer<? super T> onNext)
//表示观察者只对被观察者发送的Next & Error事件做出响应
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError)
//表示观察者只对被观察者发送的Next & Error & Complete事件做出响应
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
Action onComplete)
//表示观察者只对被观察者发送的Next & Error & Complete & onSubscribe事件做出响应
public final Disposable subscribe(Consumer<? super T> onNext, Consumer<? super Throwable> onError,
Action onComplete, Consumer<? super Disposable> onSubscribe)
4、线程调度Scheduler
在RxJava默认规则中,事件的发出和消费都是在同一个线程中发生的,那么上面的例子来说,就是一个同步的观察者模式。观察者模式的本省就是后台处理,前台回调的异步机制,因此异步对RxJava来说是至关重要的,异步的实现则需要用到Scheduler调度器来切换线程。
在RxJava中Scheduler(调度器)相当于线程控制器,RxJava通过Scheduler来指定那一部分代码执行在哪一个线程。我们来看看简单的例子:
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> e) throws Exception {
e.onNext("RxJava:e.onNext== 第一次");
e.onComplete();
System.out.println("subscribe()线程==" + Thread.currentThread().getId());
}
}).subscribeOn(Schedulers.io())//指定被观察者subscribe()(发送事件的线程)在IO线程()
.observeOn(Schedulers.newThread())//指定观察者接收响应事件的线程在新的线程
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
//在主线程里,不受线程调度控制
System.out.println("onSubscribe()线程==" + Thread.currentThread().getId());
}
@Override
public void onNext(@NonNull String s) {
System.out.println("onNext()线程==" + Thread.currentThread().getId());
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
System.out.println("onComplete()线程==" + Thread.currentThread().getId());
}
});
- subscribeOn(): 用于指定Observable被观察者subscribe()时所发生的线程,即指定发生事件的线程
- observeOn(): 指定
Observer观察者接收&响应事件的线程,即订阅者接收事件的线程
注意:多次指定发射事件的线程只有第一次指定有效,也就是说多次调用subscribeOn()只有第一次有效,其余的会被忽略;但是多次指定订阅者接收事件的线程是可以的,也就是说每observeOn()一次,接收事件的线程就会切换一次。
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Logger.d("Observable thread is : " + Thread.currentThread().getName());
Logger.d("emit 1");
emitter.onNext(1);
}
});
Consumer<Integer> consumer = new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Logger.d("Observer thread is :" + Thread.currentThread().getName());
Logger.d("onNext: " + integer);
}
};
observable.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Logger.d("After observeOn(mainThread), current thread is: " + Thread.currentThread().getName());
}
})
.observeOn(Schedulers.io())
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Logger.d("After observeOn(io), current thread is : " + Thread.currentThread().getName());
}
}).subscribe(consumer);
RxJava中内置了很多线程项供我们选择:
- Schedulers.io(): 代表IO操作的线程,通常用于网络、读写文件等IO密集型的操作。行为模式和new Thread()差不多,只是IO的内部是一个无上限的线程池,可重用空闲的线程,更高效 (不要把计算工作放在IO内,可以避免创建不必要的线程);
- AndroidSchedulers.mainThread():Android的主线程;用于更新UI
- Schedulers.newThread(): 总是启用新线程,并在新线程中执行操作;多用于耗时操作
- Schedulers.computation(): 代表CPU计算密集型的操作,即不会被IO等操作限制性能的操作。