一 基本使用
Observable创建
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
//ObservableEmitter 发射器的意思,用来发出事件的,它可以发出三种类型的事件,通过调用emitter的onNext(T value)、onComplete()和onError(Throwable error)就可以分别发出next事件、complete事件和error事件。
}
});
Observer创建
Observer<Integer> observer = new Observer<Integer>(){
@Override
public void onSubscribe(Disposable d) {
//开关的意思,当调用它的dispose()方法时,它就会切断事件的接受,导致观察者接受不到事件。这个可以用作当页面销毁时,取消网络请求。
}
@Override
public void onNext(Integer integer) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
};
订阅被观察者与观察者
observable.subscribe(observer);
一个observable可能没有观察者订阅,也可以多个观察者订阅,当观察者和被观察者建立联系后,被观察者可以通过onNext发送事件,也可以发送onComplete标志事件完成,被观察者发送onComplete之后,可以继续发送,而观察者接受到onComplete之后,就不会继续接收事件。
onComplete和onError必须唯一并且互斥。
subscribe有多个方法的重载,带有一个参数的Consumer方法,表示下游可以只关心onNext方法。
二 线程控制
默认情况下,观察者和被观察者工作在主线程。通常我们的需求是在子线程做耗时操作,然后回到主线程中来操作UI。此时我们可以用线程控制来达到这一目的。
observable
.subscribeOn(Schedulers.io()) //subscribeOn被观察者工作的线程
.observeOn(AndroidSchedulers.mainThread()) //observeOn 观察者工作的线程
.subscribe(observer);
RxJava内置线程选项:
1.Schedulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作,内部用线程池维护。
2.Schedulers.computation() 代表CPU计算密集型的操作, 例如需要大量计算的操作
3.Schedulers.newThread() 代表一个常规的新线程
4.AndroidSchedulers.mainThread() 代表Android的主线程
注意:
1.多次指定被观察者的线程只有第一次指定的有效, 也就是说多次调用subscribeOn() 只有第一次的有效, 其余的会被忽略.
2.多次指定观察者的线程是可以的, 也就是说每调用一次observeOn() , 下游的线程就会切换一次.
三 操作符
< 1 >.map
map是RxJava中最简单的一个变换操作符, 它的作用就是对observable发送的每一个事件应用一个函数, 使得每一个事件都按照指定的函数去变化.
eg:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
}
}).map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return "this is " + integer;
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
System.out.println(s);
}
});
通过Map可以将Observable发送的事件转换为任意的类型。
< 2 >. flatmap
FlatMap将一个发送事件的Observable变换为多个发送事件的Observables,然后将它们发射的事件合并后放进一个单独的Observable里.
eg:
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(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(Integer integer) throws Exception {
List<String> list = new ArrayList<>();
for(int i = 0; i<3; i++){
list.add("I am value " + integer);
}
return Observable.fromIterable(list).delay(10, TimeUnit.MILLISECONDS);
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
System.out.println(s);
}
});
注意:flatmap并不能保证事件的顺序,如果需要保证事件的顺序可以使用concatmap,用法和flatmap一样。
< 3 >.zip
zip通过一个函数将多个Observable发送的事件结合到一起,然后发送这些组合到一起的事件. 它按照严格的顺序应用这个函数。它只发射与发射数据项最少的那个Observable一样多的数据。
Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
}
}).subscribeOn(Schedulers.io());
Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
}
}).subscribeOn(Schedulers.io());
Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
@Override
public String apply(Integer integer, String s) throws Exception {
return "";
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
}
});
四. 背压 Backpressure
< 1 >.原理引入
当observable和observer工作在不同线程时,它们之间不能直接通信,当observable发送一个事件时,是放在一个容器(具体就是一个队列)里面的,当容器里面有事件时,才会向observer发送事件。而当observable发送事件太快,observer取事件太慢,容器就会一直放事件,最后会因为容器事件越来越多,最后导致容器OOM了。
这种observable产生事件的速度很快,而observer处理很慢,事件会堆积起来,最终挤爆你的内存,导致程序崩溃(MissingBackpressureException异常)。
至此,就可以引出背压(Backpressure)的概念:背压是指在异步场景中,被观察者发送事件速度远快于观察者的处理速度的情况下,一种告诉上游的被观察者降低发送速度的策略。
关于背压,可以看这里
< 2 >.解决方案
a. 使用filter过滤掉不需要的数据
b. 使用sample每隔一段时间从observable取出事件,发送给下游。
c. 延时降低observable发送事件的速度。
d.使用flowable解决。
大致就是从数量和速度上解决。
五.Flowable
这里把被观察者指定为flowable,观察者指定为subscriber。
eg:
Flowable<Integer> flowable = Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> e) throws Exception {
}
//流速不均匀直接抛异常
}, BackpressureStrategy.ERROR);
Subscriber<Integer> subscriber = new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
}
@Override
public void onNext(Integer integer) {
}
@Override
public void onError(Throwable t) {
}
@Override
public void onComplete() {
}
};
flowable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(subscriber);
和observable不同的是,这里增加了一个参数,用来处理上下游流速不均衡的时候应该怎么处理的办法,在例子中直接抛出了一个BackpressureStrategy.ERROR异常,也就是MissingBackpressureException异常。同时观察者中不是再使用Disposable,而是使用Subscription,与Disposable不同的是,这种采用的是响应式拉取,当在onSubscribe方法中调用了request方法时,observable会根据request的事件数量发相应数量的事件。observable不会再一直发事件。如果不调用request方法,在同一线程,就会抛MissingBackpressureException异常,在不同线程,observable就会先把事件放到一个容器,大小为128。当observer调用request才会发送事件。