RxJava和Retrofit的依赖
//rxjava依赖
implementation'io.reactivex.rxjava2:rxjava:2.0.1'
implementation'io.reactivex.rxjava2:rxandroid:2.0.1'
//retrofit
compile'com.squareup.retrofit2:retrofit:2.1.0'
//Gson converter
compile'com.squareup.retrofit2:converter-gson:2.1.0'
/RxJava2 Adapter
compile'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
//okhttp
compile'com.squareup.okhttp3:okhttp:3.4.1'
compile'com.squareup.okhttp3:logging-interceptor:3.4.1'
1. RxJava链式写法,线程切换
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(ObservableEmitter emitter) throws Exception {
Log.d(TAG, "emitter 1");
emitter.onNext("1");
Log.d(TAG, "emitter 2");
emitter.onNext("2");
Log.d(TAG, "emitter onComplete");
emitter.onComplete();
Log.d(TAG, "emitter 3");
emitter.onNext("3");
}
}).subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.observeOn(Schedulers.newThread())
.subscribe(new Observer() {
private int i;
@Override
public void onSubscribe(Disposable disposable) {
TestRxJavaActivity.this.disposable = disposable;
Log.d(TAG, "onSubscribe");
}
@Override
public void onNext(String value) {
Log.d(TAG, "onNext value:" + value);
i++;
if (i == 2) {
Log.d(TAG, "dispose");
disposable.dispose();
Log.d(TAG, "isDisposed:" + disposable.isDisposed());
}
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}});
ObservableEmitter:发射器,用来发出事件,可以发出三种类型的事件,通过调用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事件会导致程序会崩溃.
2. RxJava中内置的线程
Schedulers.io() 代表io操作的线程, 通常用于网络,读写文件等io密集型的操作
Schedulers.computation() 代表CPU计算密集型的操作, 例如需要大量计算的操作
Schedulers.newThread() 代表一个常规的新线程
AndroidSchedulers.mainThread() 代表Android的主线程
这些内置的Scheduler已经足够满足我们开发的需求, 因此我们应该使用内置的这些选项, 在RxJava内部使用的是线程池来维护这些线程, 所以效率也比较高.
线程切换:
.subscribeOn(Schedulers.newThread()) //指定的是上游发送事件的线程
.observeOn(AndroidSchedulers.mainThread()) //指定的是下游接收事件的线程.
多次指定上游的线程只有第一次指定的有效, 也就是说多次调用subscribeOn() 只有第一次的有效, 其余的会被忽略.
多次指定下游的线程是可以的, 也就是说每调用一次observeOn() , 下游的线程就会切换一次.
3. 在Activity退出时要切断水管(订阅),调用Disposable的dispose()方法切断连接,如果有多个Disposable,使用RxJava中内置的容器CompositeDisposable, 每得到一个Disposable就调用 CompositeDisposable.add(),将它添加到容器中,在Activity退出的时候, 调用CompositeDisposable.clear() 即可切断所有的水管(订阅)
4. 最简单的map转换操作符:
通过map, 可以将上游发来的事件转换为任意的类型, 可以是一个Object, 也可以是一个集合.
示例代码:
.map(new Function
//将Integer转成String类型
@Override
public String apply(Integer integer) throws Exception{
return"This is result "+ integer;
} })
5. flatMap操作符:
上游每发送一个事件, flatMap都将创建一个新的水管, 然后发送转换之后的新的事件, 下游接收到的就是这些新的水管发送的数据.这里需要注意的是, flatMap并不保证事件的顺序,也就是图中所看到的, 并不是事件1就在事件2的前面. 如果需要保证顺序则需要使用concatMap,用法一模一样
示例代码:
.concatMap(newFunction
@Override
public ObservableSource apply(Integer integer)throws Exception{
final List list =new ArrayList<>();
for(int i =0; i <3; i++) {
list.add("I am value "+ integer);
}
return Observable.fromIterable(list);
} })
实践示例:可以实现嵌套请求,如注册完成去登录就可以使用concatMap或者flatMap了
6. zip操作符通过一个函数将多个Observable发送的事件结合到一起,然后发送这些组合到一起的事件. 它按照严格的顺序应用这个函数。它只发射与发射数据项最少的那个Observable一样多的数据。并且一个事件只能被使用一次, 组合的顺序是严格按照事件发送的顺序来进行的.并且发送的事件都是在同一线程,需要切换线程,发送事件才可以在不同线程同步进行发送.
示例代码:
Observable.zip(observable1, observable2,new BiFunction
@Override
public String apply(Integer integer, String s)throws Exception{
return integer + s;
} })
实践示例:比如一个界面需要展示用户的一些信息, 而这些信息分别要从两个服务器接口中获取, 而只有当两个都获取到了之后才能进行展示, 这个时候就可以用Zip了
7. filter:过滤操作符,过滤上游事件
示例代码:
.filter(new Predicate() {
@Override
public boolean test(Integer integer)throws Exception {
return integer%10==0;
}
})
8. sample:取样操作符,每隔指定的时间就从上游中取出一个事件发送给下游
示例代码:.sample(2, TimeUnit.SECONDS)//没个两秒sample取样一次上游事件
9.Flowable的使用
上游是Flowable,下游是Subscriber,链接不变,和Observable用法一样,只是多了一个 背压策略参数:BackpressureStrategy.ERROR;
Flowable在设计的时候采用了一种新的思路也就是响应式拉取的方式来更好的解决上下游流速不均衡的问题;
FLowable相比Observable, 在性能方面有些不足, 毕竟FLowable内部为了实现响应式拉取做了更多的操作, 性能有所丢失也是在所难免;
Flowable默认最多可以存放128个事件;
背压策略:
BackpressureStrategy.ERROR:当下游没有处理事件能力是抛出 MissingBackpressureException异常
BackpressureStrategy.BUFFER:上游水缸没有大小限制;
BackpressureStrategy.DROP: 直接把存不下的事件丢弃;
BackpressureStrategy.LATEST:只保留最新的事件;
注:Latest和Drop的区别在于Latest总是能获取到最后最新的事件;
Flowable
@Override
public void subscribe(FlowableEmitter
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();
} }, BackpressureStrategy.ERROR);//增加了一个参数,背压策略
Subscriber
@Override
publicvoid onSubscribe(Subscription s){
Log.d(TAG,"onSubscribe");
s.request(Long.MAX_VALUE);//注意这句代码
}
@Override
public void onNext(Integer integer){
Log.d(TAG,"onNext: "+ integer); }
@Override
public void onError(Throwable t){
Log.w(TAG,"onError: ", t); }
@Override
public void onComplete(){
Log.d(TAG,"onComplete");
} };
upstream.subscribe(downstream);
10.下游Subscriber的onSubcribe方法中传递的是一个Subscription,它也是上下游的一个开关,调用Subscription.cancel()也可以切断水管,同时也增加一个Subscription.requset(3)方法,该方法代表下游处理事件的能力,参数是几就是代表能处理几个事件
11.同一线程中在上游使用FlowableEmitter.requested()获取下游处理事件能力的多少;
当上下游工作在不同的线程里时,每一个线程里都有一个requested方法,而我们调用request(1000)时,实际上改变的是下游线程中的requested,而上游中的requested的值是由RxJava内部调用request(n)去设置的,这个调用会在合适的时候自动触发。
注:不同线程中下游每消费96个事件便会自动触发内部的request()去设置上游的requested的值, 发送事件前先判断当前的requested的值是否大于0,若等于0则说明下游处理不过来了,则需要等待
12.只有onNext()事件才会消耗事件,complete和error事件不会消耗requested;