最近在研究Android网络请求的相关框架,目前比较主流的就是RxJava结合Retrofit的使用,看了大神Carson_Ho对该框架的剖析,学习的同时也在此同步记录总结,后面用的时候可以直接查阅此文。
RxJava
RxJava是一个 基于事件流、实现异步操作的库,包含各种各样的操作符,其基于链式的调用方式可以完成丰富的功能需求,使用方便简单,深受大家的喜欢。
在这里,我总结了关于RxJava的多种操作符的使用,通过结合多种操作符即可完成大多数功能需求,这里介绍的类似于API一样的调用方式,每个操作符通过一个小案例实现,并在案例中描述了操作符的具体作用。
创建被观察者
字段 | 特点 |
---|---|
create | 最原始的创建被观察者的方式,最繁琐却能定义最复杂的事件 |
just | 快速创建多个事件(小于10个) |
fromArray | 从数组快速创建多个事件(可大于10个) |
fromIterable | 通过集合创建事件(可多个) |
empty | 仅发送Complete事件,直接通知完成 |
error | 仅发送Error事件,直接通知异常 |
never | 不发送任何事件 |
defer | 直到有观察者订阅时,才动态创建被观察者对象 & 发送事件,保证事件是最新的。 |
timer | 延迟发送事件 |
interval,intervalRange | 周期性发送事件 |
range | 发送指定范围的事件 |
变换事件
字段 | 特点 |
---|---|
map | 将被观察者发送的事件转换为任意的类型事件 |
flatMap | 将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列进行发送 |
concatMap | 与FlatMap的 区别在于:拆分 & 重新合并生成的事件序列 的顺序 = 被观察者旧序列生产的顺序 |
buffer | 定期从 被观察者需要发送的事件中 获取一定数量的事件 & 放到缓存区中,最终发送 |
组合操作符
字段 | 特点 |
---|---|
concat | 组合多个被观察者(小于4个)一起发送数据,合并后 按发送顺序串行执行 |
concatArray | 组合多个被观察者(大于4个)一起发送数据,合并后 按发送顺序串行执行 |
merge | 组合多个被观察者(小于4个)一起发送数据,合并后 按时间线并行执行 |
mergeArray | 组合多个被观察者(大于4个)一起发送数据,合并后 按时间线并行执行 |
concatArrayDelayError | 发生error事件时,等其他被观察者发送完事件之后再发送error事件 |
zip | 合并多个被观察者(Observable)发送的事件,生成一个新的事件序列(即组合过后的事件序列),并最终发送 |
combineLatest | 与Zip的区别:Zip+ 按个数合并,即1对1合并;CombineLatest = 按时间合并,即在同一个时间点上合并 |
reduce | 把被观察者需要发送的事件聚合成1个事件 & 发送 |
collect | 将被观察者Observable发送的数据事件收集到一个数据结构里 |
startWith | 在一个被观察者发送事件前,追加发送一些数据 / 一个新的被观察者 |
count | 统计被观察者发送事件的数量 |
功能操作符
字段 | 特点 |
---|---|
delay | 使得被观察者延迟一段时间再发送事件 |
doOnEach | 当Observable每发送1次数据事件就会调用1次 |
doOnNext | 执行onNext事件前调用,这里已经可以拿到事件结果了 |
doAfterNext | 执行onNext事件后调用 |
doOnComplete | Observable正常发送事件完毕后调用 |
doOnError | Observable发送错误事件时调用 |
doOnSubscribe | 观察者订阅时调用 |
doAfterTerminate | Observable发送事件完毕后调用,无论正常发送完毕 / 异常终止 |
doFinally | 最后执行 |
onErrorReturn | 遇到错误时,发送1个特殊事件 & 正常终止 |
onErrorResumeNext | 遇到Throwable错误时,发送1个新的Observable |
onExceptionResumeNext | 遇到Exception错误时,发送1个新的Observable |
retry | 接收到 onError()时,重新订阅 & 发送事件 |
retryWhen | 遇到error事件才会回调 |
repeat | 无条件地、重复发送 被观察者事件 |
repeatWhen | 将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据传递给1个新被观察者,以此决定是否重新订阅 & 发送原来的 Observable |
在实现功能之前可以在此复习一下各操作符,然后结合功能组合操作符,最终实现自己想要的效果。
下面详细讲一下每个字段的使用,在这之前首先说明一下本次使用的RxJava的版本:
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
引入包之后即可使用RxJava的字段,在这里我写了一个类RxJavaUtil,这里把每个字段的用法都简单写了一下,想体验一下使用效果的直接复制这个类,并在Activity中运行一下即可。这里主要参考的是Carson_Ho大神的RxJava系列讲解文章,再次感谢大佬的无私奉献。
public class RxJavaUtil {
private static final String TAG = RxJavaUtil.class.getSimpleName();
// <-----------------------------------创建操作符----------------------------------------------->
// Integer观察者,定义接收到事件后的处理
Observer observer = new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
System.out.println("开始采用subscribe连接");
}
@Override
public void onNext(Integer value) {
System.out.println("接收到了事件"+ value);
}
@Override
public void onError(Throwable e) {
System.out.println("对Error事件作出响应");
}
@Override
public void onComplete() {
System.out.println("对Complete事件作出响应");
}
};
// Long观察者,延时监听会发送long value
Observer<Long> longObserver = new Observer<Long>() {
@Override
public void onSubscribe(Disposable d) {
System.out.println("开始采用subscribe连接");
}
@Override
public void onNext(Long value) {
System.out.println("接收到了事件"+ value);
}
@Override
public void onError(Throwable e) {
System.out.println("对Error事件作出响应");
}
@Override
public void onComplete() {
System.out.println("对Complete事件作出响应");
}
};
/**
* 1.定义好被观察者以及被订阅之后发送的事件
* 2.定义观察者以及接收到事件后的相应
* 3.订阅,可多次订阅,多次订阅则多次连接并多次触发响应
*/
public void createObservableByCreate() {
Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}
});
observable.subscribe(observer);
}
/**
* 快速创建Observable,与createObservableByCreate方法类似,只是创建Observable更为便捷
* 创建时传入整型1、2、3、4
* 在创建后就会发送这些对象,相当于执行了onNext(1)、onNext(2)、onNext(3)、onNext(4)
*
* 应用场景:快速创建 被观察者对象(Observable) & 发送10个以下事件
*/
public void createObservableByJust() {
// 创建时传入整型1、2、3、4
// 在创建后就会发送这些对象,相当于执行了onNext(1)、onNext(2)、onNext(3)、onNext(4)
Observable observable = Observable.just(1, 2, 3,4);
observable.subscribe(observer);
}
/**
* 通过数组创建Observable,与createObservableByJust类似,但可以传递更多的事件
*
* 应用场景:快速创建 被观察者对象(Observable) & 发送10个以上事件
*/
public void createObservableByArray() {
Integer[] items = {1,2,3,4,5,6};
Observable observable = Observable.fromArray(items);
observable.subscribe(observer);
}
/**
* 通过集合创建Observable,与createObservableByArray类似
*
* 应用场景:快速创建 被观察者对象(Observable) & 发送10个以上事件(集合形式)
*/
public void createObservableByIterable() {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add(i);
}
Observable observable = Observable.fromIterable(list);
observable.subscribe(observer);
}
/**
* 用来测试的一些Observable
*/
public void createObservableForTest() {
// 该方法创建的被观察者对象发送事件的特点:仅发送Complete事件,直接通知完成
Observable emptyObservable = Observable.empty();
emptyObservable.subscribe(observer);
// 该方法创建的被观察者对象发送事件的特点:仅发送Error事件,直接通知异常
Observable errorObservable = Observable.error(new RuntimeException());
errorObservable.subscribe(observer);
// 该方法创建的被观察者对象发送事件的特点:不发送任何事件
Observable neverObservable = Observable.never();
neverObservable.subscribe(observer);
}
/**
* 通过 Observable工厂方法创建被观察者对象(Observable)
* 每次订阅后,都会得到一个刚创建的最新的Observable对象,这可以确保Observable对象里的数据是最新的
* 直到有观察者(Observer )订阅时,才动态创建被观察者对象(Observable) & 发送事件
*
* 因为是在订阅时才创建,所以i值会取第2次的赋值
*/
int i;
public void createObservableByDefer() {
i = 10;
Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> call() throws Exception {
return Observable.just(i);
}
});
i = 100;
observable.subscribe(observer);
}
/**
* 延迟指定时间后,发送1个数值0(Long类型)
* 本质 = 延迟指定时间后,调用一次 onNext(0)
*/
public void createObservableByTimer() {
Observable observable = Observable.timer(2, TimeUnit.SECONDS);
observable.subscribe(longObserver);
}
/**
* 发送事件的特点:每隔指定时间就发送事件
* 发送的事件序列 = 从0开始、无限递增1的的整数序列
*/
public void createObservableByInterval() {
Observable observable = Observable.interval(1, 1, TimeUnit.SECONDS);
observable.subscribe(longObserver);
}
/**
* 发送事件的特点:每隔指定时间 就发送 事件,可指定发送的数据的数量
* a. 发送的事件序列 = 从0开始、无限递增1的的整数序列
* b. 作用类似于interval(),但可指定发送的数据的数量
*/
public void createObservableByIntervalRange() {
// 参数说明:
// 参数1 = 事件序列起始点;
// 参数2 = 事件数量;
// 参数3 = 第1次事件延迟发送时间;
// 参数4 = 间隔时间数字;
// 参数5 = 时间单位
Observable observable = Observable.intervalRange(3, 10, 2, 1, TimeUnit.SECONDS);
observable.subscribe(longObserver);
}
/**
* 发送事件的特点:连续发送 1个事件序列,可指定范围
* 作用类似于intervalRange(),但区别在于:无延迟发送事件
* 还有一个rangeLong方法,与该方法使用一致
*/
public void createObservableByRange() {
Observable observable = Observable.range(1, 3);
observable.subscribe(observer);
}
// <----------------------------------------------变换操作符------------------------------------->
// 接收转换后的事件
Consumer<String> consumer = new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
System.out.println(s);
}
};
/**
* 对被观察者发送的每1个事件都通过指定的函数处理,从而变换成另外一种事件,即, 将被观察者发送的事件转换为任意的类型事件。
* 应用场景:数据类型转换
*/
@SuppressLint("CheckResult")
public void handleEventByMap() {
Observable<Integer> observable = Observable.just(1,2,3,4);
observable.map(new Function<Integer, String>() {
@Override
public String apply(Integer integer) throws Exception {
return "变换前 : " + integer + "变换后" + integer.toString();
}
}).subscribe(consumer);
}
/**
* 将被观察者发送的事件序列进行 拆分 & 单独转换,再合并成一个新的事件序列,最后再进行发送
*
* 应用场景:无序的将被观察者发送的整个事件序列进行变换
* 新合并生成的事件序列顺序是无序的,即 与旧序列发送事件的顺序无关
*/
@SuppressLint("CheckResult")
public void handleEventByFlatMap() {
Observable<Integer> observable = Observable.just(1,2,3,4);
observable.flatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Integer integer) throws Exception {
final List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("我是事件 " + integer + "拆分后的子事件" + i);
// 通过flatMap中将被观察者生产的事件序列先进行拆分,再将每个事件转换为一个新的发送三个String事件
// 最终合并,再发送给被观察者
}
return Observable.fromIterable(list);
}
}).subscribe(consumer);
}
/**
* 与FlatMap()的 区别在于:拆分 & 重新合并生成的事件序列 的顺序 = 被观察者旧序列生产的顺序
* 新合并生成的事件序列顺序是有序的,即 严格按照旧序列发送事件的顺序
*
* 应用场景:有序的将被观察者发送的整个事件序列进行变换
*/
@SuppressLint("CheckResult")
public void handleEventByConcatMap() {
Observable<Integer> observable = Observable.just(1,2,3,4);
observable.concatMap(new Function<Integer, ObservableSource<String>>() {
@Override
public ObservableSource<String> apply(Integer integer) throws Exception {
final List<String> list = new ArrayList<>();
for (int i = 0; i < 3; i++) {
list.add("我是事件 " + integer + "拆分后的子事件" + i);
// 通过flatMap中将被观察者生产的事件序列先进行拆分,再将每个事件转换为一个新的发送三个String事件
// 最终合并,再发送给被观察者
}
return Observable.fromIterable(list);
}
}).subscribe(consumer);
}
/**
* 定期从 被观察者(Obervable)需要发送的事件中 获取一定数量的事件 & 放到缓存区中,最终发送
*
* 应用场景:缓存被观察者发送的事件
*/
public void handleEventByBuffer() {
Observable.just(1, 2, 3, 4, 5)
.buffer(3, 1) // 设置缓存区大小 & 步长
// 缓存区大小 = 每次从被观察者中获取的事件数量
// 步长 = 每次获取新事件的数量
.subscribe(new Observer<List<Integer>>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(List<Integer> stringList) {
//
System.out.println(" 缓存区里的事件数量 = " + stringList.size());
for (Integer value : stringList) {
System.out.println(" 事件 = " + value);
}
}
@Override
public void onError(Throwable e) {
System.out.println("对Error事件作出响应" );
}
@Override
public void onComplete() {
System.out.println("对Complete事件作出响应");
}
});
}
// <--------------------------------------------------组合/合并操作符--------------------------------->
/**
* 组合多个被观察者一起发送数据,合并后 按发送顺序串行执行
* 组合被观察者数量≤4个
*/
public void concatObservable() {
Observable.concat(Observable.just(1, 2, 3),
Observable.just(4, 5, 6),
Observable.just(7, 8, 9),
Observable.just(10, 11, 12))
.subscribe(observer);
}
/**
* 组合多个被观察者一起发送数据,合并后 按发送顺序串行执行
* 组合被观察者数量>4个
*/
public void concarArrayObservable() {
Observable.concatArray(Observable.just(1, 2, 3),
Observable.just(4, 5, 6),
Observable.just(7, 8, 9),
Observable.just(10, 11, 12),
Observable.just(13, 14, 15))
.subscribe(observer);
}
/**
* 组合多个被观察者一起发送数据,合并后 按时间线并行执行
* 组合被观察者数量≤4个
*/
public void mergeObservable() {
Observable.merge(
// 从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
// 从2开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS))
.subscribe(longObserver);
}
/**
* 组合多个被观察者一起发送数据,合并后 按时间线并行执行
* 组合被观察者数量>4个
*/
public void mergeArrayObservable() {
Observable.mergeArray(
Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
Observable.intervalRange(2, 3, 1, 1, TimeUnit.SECONDS),
Observable.intervalRange(4, 3, 1, 1, TimeUnit.SECONDS),
Observable.intervalRange(6, 3, 1, 1, TimeUnit.SECONDS),
Observable.intervalRange(8, 3, 1, 1, TimeUnit.SECONDS),
Observable.intervalRange(10, 3, 1, 1, TimeUnit.SECONDS))
.subscribe(longObserver);
}
/**
* 使用concat和merge操作符时
* 若其中一个Observable发出了onError事件,则会马上终止其他被观察者的事件发送
* 通过DelayError操作符,可以等其他被观察者发送完事件之后再发送error事件
*
* 下面演示了concatArrayDelayError的使用,concatDelayError,mergeDelayError,mergeArrayDelayError,combineLatestDelayError使用相同
*/
public void concatDelayErrorObservable() {
Observable.concatArrayDelayError(
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onError(new NullPointerException()); // 发送Error事件,因为使用了concatDelayError,所以第2个Observable将会发送事件,等发送完毕后,再发送错误事件
emitter.onComplete();
}
}),
Observable.just(4, 5, 6))
.subscribe(observer);
}
/**
* 合并多个被观察者(Observable)发送的事件,生成一个新的事件序列(即组合过后的事件序列),并最终发送
*
* 事件组合方式 = 严格按照原先事件序列 进行对位合并
* 最终合并的事件数量 = 多个被观察者(Observable)中数量最少的数量
*
* 尽管被观察者2的事件D没有事件与其合并,但还是会继续发送
* 若在被观察者1 & 被观察者2的事件序列最后发送onComplete()事件,则被观察者2的事件D也不会发送
*
* 应用场景:合并网络请求的发送,统一显示结果(RxJava+Retrofit)
*/
public void zipObservable() {
// <-- 创建第1个被观察者 -->
Observable<Integer> observable1 = Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
Log.d(TAG, "被观察者1发送了事件1");
emitter.onNext(1);
// 为了方便展示效果,所以在发送事件后加入2s的延迟
Thread.sleep(1000);
Log.d(TAG, "被观察者1发送了事件2");
emitter.onNext(2);
Thread.sleep(1000);
Log.d(TAG, "被观察者1发送了事件3");
emitter.onNext(3);
emitter.onComplete();
}
}).subscribeOn(Schedulers.io()); // 设置被观察者1在工作线程1中工作
//<-- 创建第2个被观察者 -->
Observable<String> observable2 = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
Log.d(TAG, "被观察者2发送了事件A");
emitter.onNext("A");
Thread.sleep(1000);
Log.d(TAG, "被观察者2发送了事件B");
emitter.onNext("B");
Thread.sleep(1000);
Log.d(TAG, "被观察者2发送了事件C");
emitter.onNext("C");
Log.d(TAG, "被观察者2发送了事件D");
emitter.onNext("D");
emitter.onComplete();
}
}).subscribeOn(Schedulers.newThread());// 设置被观察者2在工作线程2中工作
// 假设不作线程控制,则该两个被观察者会在同一个线程中工作,即发送事件存在先后顺序,而不是同时发送
//<-- 使用zip变换操作符进行事件合并 -->
// 注:创建BiFunction对象传入的第3个参数 = 合并后数据的数据类型
Observable.zip(observable1, observable2, new BiFunction<Integer, String, String>() {
@Override
public String apply(Integer integer, String string) throws Exception {
return integer + string;
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.d(TAG, "onSubscribe");
}
@Override
public void onNext(String value) {
Log.d(TAG, "最终接收到的事件 = " + value);
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "onError");
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete");
}
});
}
/**
* 当两个Observables中的任何一个发送了数据后,将先发送了数据的Observables 的最新(最后)一个数据与
* 另外一个Observable发送的每个数据结合,最终基于该函数的结果发送数据
*
* 与Zip()的区别:Zip() = 按个数合并,即1对1合并;CombineLatest() = 按时间合并,即在同一个时间点上合并
*/
@SuppressLint("CheckResult")
public void conbineLatestObservable() {
Observable.combineLatest(
// 第1个发送数据事件的Observable
Observable.just(1L, 2L, 3L),
// 第2个发送数据事件的Observable:从0开始发送、共发送3个数据、第1次事件延迟发送时间 = 1s、间隔时间 = 1s
Observable.intervalRange(0, 3, 1, 1, TimeUnit.SECONDS),
new BiFunction<Long, Long, Long>() {
@Override
public Long apply(Long o1, Long o2) throws Exception {
// o1 = 第1个Observable发送的最新(最后)1个数据
// o2 = 第2个Observable发送的每1个数据
Log.e(TAG, "合并的数据是: "+ o1 + " "+ o2);
return o1 + o2;
// 合并的逻辑 = 相加
// 即第1个Observable发送的最后1个数据 与 第2个Observable发送的每1个数据进行相加
}
}).subscribe(new Consumer<Long>() {
@Override
public void accept(Long s) throws Exception {
Log.e(TAG, "合并的结果是: "+s);
}
});
}
/**
* 把被观察者需要发送的事件聚合成1个事件 & 发送
* 聚合的逻辑根据需求撰写,但本质都是前2个数据聚合,然后与后1个数据继续进行聚合,依次类推
*/
@SuppressLint("CheckResult")
public void reduceObservable() {
Observable.just(1,2,3,4)
.reduce(new BiFunction<Integer, Integer, Integer>() {
// 在该复写方法中复写聚合的逻辑
@Override
public Integer apply(@NonNull Integer s1, @NonNull Integer s2) throws Exception {
Log.e(TAG, "本次计算的数据是: "+s1 +" 乘 "+ s2);
return s1 * s2;
// 本次聚合的逻辑是:全部数据相乘起来
// 原理:第1次取前2个数据相乘,之后每次获取到的数据 = 返回的数据x原始下1个数据每
}
}).subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer s) throws Exception {
Log.e(TAG, "最终计算的结果是: "+s);
}
});
}
/**
* 将被观察者Observable发送的数据事件收集到一个数据结构里
*/
@SuppressLint("CheckResult")
public void collectObservable() {
Observable.just(1, 2, 3 ,4, 5, 6)
.collect(
// 1. 创建数据结构(容器),用于收集被观察者发送的数据
new Callable<ArrayList<Integer>>() {
@Override
public ArrayList<Integer> call() throws Exception {
return new ArrayList<>();
}
// 2. 对发送的数据进行收集
}, new BiConsumer<ArrayList<Integer>, Integer>() {
@Override
public void accept(ArrayList<Integer> list, Integer integer)
throws Exception {
// 参数说明:list = 容器,integer = 后者数据
list.add(integer);
// 对发送的数据进行收集
}
}).subscribe(new Consumer<ArrayList<Integer>>() {
@Override
public void accept(@NonNull ArrayList<Integer> s) throws Exception {
Log.e(TAG, "本次发送的数据是: "+s);
}
});
}
/**
* 在一个被观察者发送事件前,追加发送一些数据 / 一个新的被观察者
*/
public void startWithObservable() {
// <-- 在一个被观察者发送事件前,追加发送一些数据 -->
// 注:追加数据顺序 = 后调用先追加
Observable.just(4, 5, 6)
.startWith(0) // 追加单个数据 = startWith()
.startWithArray(1, 2, 3) // 追加多个数据 = startWithArray()
.subscribe(observer);
// <-- 在一个被观察者发送事件前,追加发送被观察者 & 发送数据 -->
// 注:追加数据顺序 = 后调用先追加
Observable.just(4, 5, 6)
.startWith(Observable.just(1, 2, 3))
.subscribe(observer);
}
/**
* 统计被观察者发送事件的数量
*/
@SuppressLint("CheckResult")
public void countEvent() {
Observable.just(1, 2, 3, 4)
.count()
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
Log.e(TAG, "发送的事件数量 = "+aLong);
}
});
}
// <--------------------------------------------------功能操作符--------------------------------->
/**
* 使得被观察者延迟一段时间再发送事件
*/
public void delaySendEvent() {
// 指定延迟时间 & 调度器 & 错误延迟
// 参数1 = 延迟时间;参数2 = 时间单位;参数3 = 线程调度器;参数4 = 错误通知是否延迟
Observable.just(1, 2, 3)
.delay(3, TimeUnit.SECONDS, Schedulers.newThread(), true) // 延迟3s再发送,由于使用类似,所以此处不作全部展示
.subscribe(observer);
}
/**
* 在某个事件的生命周期中调用
*/
public void doOnObservable() {
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onNext(3);
e.onError(new Throwable("发生错误了"));
}
})
// 1. 当Observable每发送1次数据事件就会调用1次
.doOnEach(new Consumer<Notification<Integer>>() {
@Override
public void accept(Notification<Integer> integerNotification) throws Exception {
Log.d(TAG, "doOnEach: " + integerNotification.getValue());
}
})
// 2. 执行onNext事件前调用,这里已经可以拿到事件结果了
.doOnNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "doOnNext: " + integer);
}
})
// 3. 执行onNext事件后调用
.doAfterNext(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.d(TAG, "doAfterNext: " + integer);
}
})
// 4. Observable正常发送事件完毕后调用
.doOnComplete(new Action() {
@Override
public void run() throws Exception {
Log.e(TAG, "doOnComplete: ");
}
})
// 5. Observable发送错误事件时调用
.doOnError(new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
Log.d(TAG, "doOnError: " + throwable.getMessage());
}
})
// 6. 观察者订阅时调用
.doOnSubscribe(new Consumer<Disposable>() {
@Override
public void accept(@NonNull Disposable disposable) throws Exception {
Log.e(TAG, "doOnSubscribe: ");
}
})
// 7. Observable发送事件完毕后调用,无论正常发送完毕 / 异常终止
.doAfterTerminate(new Action() {
@Override
public void run() throws Exception {
Log.e(TAG, "doAfterTerminate: ");
}
})
// 8. 最后执行
.doFinally(new Action() {
@Override
public void run() throws Exception {
Log.e(TAG, "doFinally: ");
}
})
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer value) {
Log.d(TAG, "接收到了事件"+ value );
}
@Override
public void onError(Throwable e) {
Log.d(TAG, "对Error事件作出响应");
}
@Override
public void onComplete() {
Log.d(TAG, "对Complete事件作出响应");
}
});
}
/**
* 遇到错误时,发送1个特殊事件 & 正常终止
*/
public void onErrorReturn() {
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Throwable("发生错误了"));
}
})
.onErrorReturn(new Function<Throwable, Integer>() {
@Override
public Integer apply(@NonNull Throwable throwable) throws Exception {
// 捕捉错误异常
Log.e(TAG, "在onErrorReturn处理了错误: "+throwable.toString() );
return 666;
// 发生错误事件后,发送一个"666"事件,最终正常结束
}
})
.subscribe(observer);
}
/**
* 遇到错误时,发送1个新的Observable
*
* onErrorResumeNext()拦截的错误 = Throwable;若需拦截Exception请用onExceptionResumeNext()
* 若onErrorResumeNext()拦截的错误 = Exception,则会将错误传递给观察者的onError方法
*/
public void onErrorResumeNext() {
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Throwable("发生错误了"));
}
})
.onErrorResumeNext(new Function<Throwable, ObservableSource<? extends Integer>>() {
@Override
public ObservableSource<? extends Integer> apply(@NonNull Throwable throwable) throws Exception {
// 1. 捕捉错误异常
Log.e(TAG, "在onErrorReturn处理了错误: "+throwable.toString() );
// 2. 发生错误事件后,发送一个新的被观察者 & 发送事件序列
return Observable.just(11,22);
}
})
.subscribe(observer);
}
/**
* 遇到错误时,发送1个新的Observable
*
* onExceptionResumeNext()拦截的错误 = Exception;若需拦截Throwable请用onErrorResumeNext()
* 若onExceptionResumeNext()拦截的错误 = Throwable,则会将错误传递给观察者的onError方法
*/
public void onExceptionResumeNext() {
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Exception("发生错误了"));
}
})
.onExceptionResumeNext(new Observable<Integer>() {
@Override
protected void subscribeActual(Observer<? super Integer> observer) {
observer.onNext(11);
observer.onNext(22);
observer.onComplete();
}
})
.subscribe(observer);
}
/**
* 重试,即当出现错误时,让被观察者(Observable)重新发射数据
* 接收到 onError()时,重新订阅 & 发送事件
* Throwable 和 Exception都可拦截
*
* 共五种重载方法
* <-- 1. retry() -->
* // 作用:出现错误时,让被观察者重新发送数据
* // 注:若一直错误,则一直重新发送
*
* <-- 2. retry(long time) -->
* // 作用:出现错误时,让被观察者重新发送数据(具备重试次数限制
* // 参数 = 重试次数
*
* <-- 3. retry(Predicate predicate) -->
* // 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送& 持续遇到错误,则持续重试)
* // 参数 = 判断逻辑
*
* <-- 4. retry(new BiPredicate<Integer, Throwable>) -->
* // 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送 & 持续遇到错误,则持续重试
* // 参数 = 判断逻辑(传入当前重试次数 & 异常错误信息)
*
* <-- 5. retry(long time,Predicate predicate) -->
* // 作用:出现错误后,判断是否需要重新发送数据(具备重试次数限制
* // 参数 = 设置重试次数 & 判断逻辑
*
* retryUntil()
* 具体使用类似于retry(Predicate predicate),唯一区别:返回 true 则不重新发送数据事件。
*/
public void retry() {
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Exception("发生错误了"));
e.onNext(3);
}
})
// 作用:出现错误后,判断是否需要重新发送数据(若需要重新发送 & 持续遇到错误,则持续重试
// 参数 = 判断逻辑(传入当前重试次数 & 异常错误信息)
.retry(new BiPredicate<Integer, Throwable>() {
@Override
public boolean test(@NonNull Integer integer, @NonNull Throwable throwable) throws Exception {
// 捕获异常
Log.e(TAG, "异常错误 = "+throwable.toString());
// 获取当前重试次数
Log.e(TAG, "当前重试次数 = "+integer);
//返回false = 不重新重新发送数据 & 调用观察者的onError结束
//返回true = 重新发送请求(若持续遇到错误,就持续重新发送)
return true;
}
})
.subscribe(observer);
}
/**
* 遇到错误时,将发生的错误传递给一个新的被观察者(Observable),并决定是否需要重新订阅原始被观察者(Observable)& 发送事件
*/
public void retryWhen() {
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> e) throws Exception {
e.onNext(1);
e.onNext(2);
e.onError(new Exception("发生错误了"));
e.onNext(3);
}
})
// 遇到error事件才会回调
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
// 参数Observable<Throwable>中的泛型 = 上游操作符抛出的异常,可通过该条件来判断异常的类型
// 返回Observable<?> = 新的被观察者 Observable(任意类型)
// 此处有两种情况:
// 1. 若 新的被观察者 Observable发送的事件 = Error事件,那么 原始Observable则不重新发送事件:
// 2. 若 新的被观察者 Observable发送的事件 = Next事件 ,那么原始的Observable则重新发送事件:
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {
// 1. 若返回的Observable发送的事件 = Error事件,则原始的Observable不重新发送事件
// 该异常错误信息可在观察者中的onError()中获得
return Observable.error(new Throwable("retryWhen终止啦"));
// 2. 若返回的Observable发送的事件 = Next事件,则原始的Observable重新发送事件(若持续遇到错误,则持续重试)
// return Observable.just(1);
}
});
}
})
.subscribe(observer);
}
/**
* 无条件地、重复发送 被观察者事件
*/
public void repeat() {
Observable.just(1, 2, 3, 4)
.repeat(3) // 重复创建次数 =- 3次
.subscribe(observer);
}
/**
* 将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据传递给1个新被观察者(Observable),以此决定是否重新订阅 & 发送原来的 Observable
*
* 若新被观察者(Observable)返回1个Complete / Error事件,则不重新订阅 & 发送原来的 Observable
* 若新被观察者(Observable)返回其余事件时,则重新订阅 & 发送原来的 Observable
*/
public void repeatWhen() {
Observable.just(1,2,4).repeatWhen(new Function<Observable<Object>, ObservableSource<?>>() {
@Override
// 在Function函数中,必须对输入的 Observable<Object>进行处理,这里我们使用的是flatMap操作符接收上游的数据
public ObservableSource<?> apply(@NonNull Observable<Object> objectObservable) throws Exception {
// 将原始 Observable 停止发送事件的标识(Complete() / Error())转换成1个 Object 类型数据传递给1个新被观察者(Observable)
// 以此决定是否重新订阅 & 发送原来的 Observable
// 此处有2种情况:
// 1. 若新被观察者(Observable)返回1个Complete() / Error()事件,则不重新订阅 & 发送原来的 Observable
// 2. 若新被观察者(Observable)返回其余事件,则重新订阅 & 发送原来的 Observable
return objectObservable.flatMap(new Function<Object, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Object throwable) throws Exception {
// 情况1:若新被观察者(Observable)返回1个Complete() / Error()事件,则不重新订阅 & 发送原来的 Observable
return Observable.empty();
// Observable.empty() = 发送Complete事件,但不会回调观察者的onComplete()
// return Observable.error(new Throwable("不再重新订阅事件"));
// 返回Error事件 = 回调onError()事件,并接收传过去的错误信息。
// 情况2:若新被观察者(Observable)返回其余事件,则重新订阅 & 发送原来的 Observable
// return Observable.just(1);
// 仅仅是作为1个触发重新订阅被观察者的通知,发送的是什么数据并不重要,只要不是Complete() / Error()事件
}
});
}
})
.subscribe(observer);
}
}
代码中为了少写点儿代码,很多地方是复用的Observer,但其实RxJava更多的用法是链式调用,在实际使用中可以结合各种字段并链式调用,但要注意调用时候的顺序,否则也容易出现各种意想不到的结果,比如线程错乱等。而且RxJava的魅力也在于其各种字段的链式组合,如果想要掌握RxJava,一定要各种字段的组合都尝试一遍,这样才能得心应手,否则拿到开发需求的时候,仅仅掌握各种字段用法,但不知如何组合调用,也是白学。
Retrofit
好了,RxJava的代码告一段落,下面讲一下Retrofit的使用,毕竟本文的最终目的是实现MVP+RxJava+Retrofit的结合。
Retrofit基于okhttp封装的网络请求框架, 网络请求的工作本质上是 OkHttp 完成,而 retrofit 仅负责网络请求接口的封装。
Retrofit优势,就是简洁易用,解耦,扩展性强,可搭配多种Json解析框架(例如Gson),另外还支持RxJava。
其他关于Retrofit的介绍在这里就不啰嗦了,百度一大堆,这里直接讲干货(Retrofit的使用)
首先引入Retrofit和Gson的支持,这样就可以使用Retrofit的方法以及Gson格式解析了。
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
Retrofit毕竟是网络请求,所以需要找一个可以发起网络请求并返回的网站,这里用采用有道翻译,无需注册开发者,直接可用。具体使用可以分为三步:
- 编写实体类,用于返回数据的解析
- 编写网络请求接口
- 通过Retrofit发起网络请求
下面简单讲解一下每一步,不详细描述,具体自行百度即可。
实体类
网络请求的返回结果一般是遵从某种格式的,比如json,xml,protobuff等,而实体类的编写就是为了将这些格式的结果转化,通过Adapter适配器可以将原始格式转化为我们的实体类,方便在程序中访问调用。
有道翻译的返回结果是Gson格式:
{
"type": "EN2ZH_CN",
"errorCode": 0,
"elapsedTime": 1,
"translateResult": [
[{
"src": "hello, world",
"tgt": "你好,世界"
}]
]
}
我们编写一个对应的实体类Translation
public class Translation {
private static final String TAG = Translation.class.getSimpleName();
private String type;
private int errorCode;
private int elapsedTime;
private List<List<TranslateResultBean>> translateResult;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public int getErrorCode() {
return errorCode;
}
public void setErrorCode(int errorCode) {
this.errorCode = errorCode;
}
public int getElapsedTime() {
return elapsedTime;
}
public void setElapsedTime(int elapsedTime) {
this.elapsedTime = elapsedTime;
}
public List<List<TranslateResultBean>> getTranslateResult() {
return translateResult;
}
public void setTranslateResult(List<List<TranslateResultBean>> translateResult) {
this.translateResult = translateResult;
}
public static class TranslateResultBean {
public String src;
public String tgt;
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
public String getTgt() {
return tgt;
}
public void setTgt(String tgt) {
this.tgt = tgt;
}
}
//定义 输出返回数据 的方法
public void show() {
Log.d(TAG, type);
Log.d(TAG, errorCode + "");
Log.d(TAG, elapsedTime + "");
Log.d(TAG, translateResult.get(0).get(0).src + ":" + translateResult.get(0).get(0).tgt);
}
@Override
public String toString() {
return "Translation{" +
"type='" + type + '\'' +
", errorCode=" + errorCode +
", elapsedTime=" + elapsedTime +
", translateResult=" + translateResult.get(0).get(0).tgt +
'}';
}
}
网络请求接口
通过标签来编写网络请求接口,标签众多,这里将用的比较多的标签列举了一遍,并在代码中做了详细说明。其他标签需要用到的时候可以自行查阅,用法一致,不多赘述。
public interface IGetRequest {
/**
* Retrofit把网络请求的URL分成了两部分:一部分放在Retrofit对象里,另一部分放在网络请求接口里
* 如果接口里的url是一个完整的网址,那么放在Retrofit对象里的URL可以忽略
* getCall()是接受网络请求数据的方法
*
* 这里等同于 @GET("translate?doctype=json&type=AUTO&i=keyword")
* @Path 标签可以动态设置url路径中的信息, @Query标签可以动态设置Get请求的参数信息
*/
@GET("{translate}?doctype=json&type=AUTO")
Call<Translation> getCall(@Path("translate") String translate, @Query("i") String keyword);
/**
* 这里与上面不同的地方在于字段采用map的方式填充,上面用Query的方式是一个字段一个字段的填充
* 如果@Get标签后没有跟url,可以在参数中动态设置url,这样的接口具有很大的通用性
*/
@GET
Call<Translation> getCall(@Url String url, @QueryMap HashMap<String, String> map);
/**
* 通过Post发送请求,用法与Get类似,只不过把标签换成了@Field
*/
@POST("translate")
@FormUrlEncoded
Call<Translation> postCall(@Field("doctype") String docType, @Field("type") String type, @Field("i") String i);
@POST("translate")
@FormUrlEncoded
Call<Translation> postCall(@FieldMap HashMap<String, String> map);
/**
* 替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用及更多功能拓展
*
* method:网络请求的方法(区分大小写)
* path:网络请求地址路径
* hasBody:是否有请求体
*/
@HTTP(method = "GET", path = "{translate}?doctype=json&type=AUTO&i=keyword", hasBody = false)
Call<Translation> httpCall(@Path("translate") String translate);
}
Retrofit请求
Retrofit的主要工作是配置网络请求的参数,包括请求地址,结果适配器,请求参数,结果处理回调等。需要注意,这里的参数配置要与网络请求接口配合,具体需要什么参数,怎么输入参数都是在接口中定义好的,Retrofit中的参数配置更多是执行接口的定义,所以接口的定义至关重要,这里举几个例子说明一下详细用法。
/**
* Get请求,异步返回,这里用Query标签填充字段
*/
private void getQueryRequestByCallback() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
IGetRequest request = retrofit.create(IGetRequest.class);
request.getCall("translate", "中国").enqueue(new Callback<Translation>() {
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
response.body().show();
}
@Override
public void onFailure(Call<Translation> call, Throwable t) {
Log.e(TAG, t.getMessage() + "连接失败");
}
});
}
/**
* Get请求,异步返回,这里用QueryMap标签填充字段
*/
private void getQueryMapRequestByCallback() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
IGetRequest request = retrofit.create(IGetRequest.class);
HashMap<String, String> map = new HashMap<>();
map.put("doctype", "json");
map.put("type", "AUTO");
map.put("i", "美国");
request.getCall("translate", map).enqueue(new Callback<Translation>() {
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
response.body().show();
}
@Override
public void onFailure(Call<Translation> call, Throwable t) {
Log.e(TAG, "连接失败");
}
});
}
/**
* Post请求,异步返回,这里用Field标签填充字段,用法与Get类似
*/
private void postFieldRequestByCallback() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
IGetRequest request = retrofit.create(IGetRequest.class);
Call<Translation> call = request.postCall("json", "AUTO", "韩国");
call.enqueue(new Callback<Translation>() {
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
response.body().show();
}
@Override
public void onFailure(Call<Translation> call, Throwable t) {
Log.e(TAG, "连接失败");
}
});
}
/**
* Get请求,异步返回,这里用FieldMap标签填充字段,用法与Get类似
*/
private void postFieldMapByCallback() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
HashMap<String, String> map = new HashMap<>();
map.put("doctype", "json");
map.put("type", "AUTO");
map.put("i", "日本");
IGetRequest call = retrofit.create(IGetRequest.class);
call.postCall(map).enqueue(new Callback<Translation>() {
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
response.body().show();
}
@Override
public void onFailure(Call<Translation> call, Throwable t) {
Log.e(TAG, "连接失败");
}
});
}
/**
* 通过http标签发起请求
*/
private void httpRequestByCallback() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
IGetRequest request = retrofit.create(IGetRequest.class);
request.httpCall("translate").enqueue(new Callback<Translation>() {
@Override
public void onResponse(Call<Translation> call, Response<Translation> response) {
response.body().show();
}
@Override
public void onFailure(Call<Translation> call, Throwable t) {
Log.e(TAG, "连接失败");
}
});
}
/**
* 同步返回,其他用法类似,不再举例
*/
private void postFieldMapBySync() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
HashMap<String, String> map = new HashMap<>();
map.put("doctype", "json");
map.put("type", "AUTO");
map.put("i", "日本");
IGetRequest call = retrofit.create(IGetRequest.class);
try {
Response<Translation> response = call.postCall(map).execute();
response.body().show();
} catch (IOException e) {
e.printStackTrace();
}
}
至此,RxJava和Retrofit的基础使用基本讲完了,下面进入本文的最终目标,MVP+Retrofit+RxJava结合案例。
MVP+RxJava+Retrofit
案例也很简单,采用的还是有道的网络请求,实现的也就是翻译功能,需求如下:
- 正常输入文本,可以自动识别出中英文并自动翻译出结果
- 网络请求失败时,自动重连并发起请求,并避免无限重连,有合理的重连机制
- 在重连时通过缓冲条展示,避免界面处于无反应状态
- 多次请求失败后,给出失败原因
MVP应该也不需要介绍,也没啥好说的,直接上代码吧:
首先要引入各种支持
// 此处一定要注意使用RxJava2的版本
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
// Android 支持 Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
// 衔接 Retrofit & RxJava
// 此处一定要注意使用RxJava2的版本
implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
// 支持Gson解析
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
看一下项目目录
Translation
这个在上面已经写过了,和上面的一样,就不说了
model
总共就三个类,IMvpModel定义获取网络请求的接口
public interface IMvpModel {
void getTranslation(String keyword, OnResultCallback callback);
}
MvpModelImpl是IMvpModel的实现,通过Retrofit和RxJava的结合获取网络请求结果,其中也处理了网络请求的重连机制以及重连时的UI缓冲机制,具体的细节可以自己运行调试一下,并没有什么复杂的逻辑。
public class MvpModelImpl implements IMvpModel {
private static final String TAG = MvpModelImpl.class.getSimpleName();
private static final String URL_YOUDAO = "http://fanyi.youdao.com/";
Retrofit retrofit;
int maxConnectCount = 5; // 可重试次数
int currentRetryCount = 0; // 当前已重试次数
int waitRetryTime = 0; // 重试等待时间
public MvpModelImpl() {
this.retrofit = RetrofitFactory.getInstance().createRetrofit(URL_YOUDAO);
}
@Override
public void getTranslation(String keyword, final OnResultCallback callback) {
retrofit.create(IGetRequest.class)
.getResult(keyword)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.retryWhen(new Function<Observable<Throwable>, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Observable<Throwable> throwableObservable) throws Exception {
// 参数Observable<Throwable>中的泛型 = 上游操作符抛出的异常,可通过该条件来判断异常的类型
return throwableObservable.flatMap(new Function<Throwable, ObservableSource<?>>() {
@Override
public ObservableSource<?> apply(@NonNull Throwable throwable) throws Exception {
Log.d(TAG, "发生异常 = "+ throwable.toString());
if (throwable instanceof IOException){
Log.d(TAG, "属于IO异常,需重试" );
if (currentRetryCount < maxConnectCount){
// 记录重试次数
currentRetryCount++;
Log.d(TAG, "重试次数 = " + currentRetryCount);
// 设置等待时间
waitRetryTime = 1000 + currentRetryCount* 1000;
Log.d(TAG, "等待时间 =" + waitRetryTime);
// 通知UI展示缓冲条
callback.onRetryed(currentRetryCount);
return Observable.just(1).delay(waitRetryTime, TimeUnit.MILLISECONDS);
}else{
// 若重试次数已 > 设置重试次数,则不重试
// 通过发送error来停止重试(可在观察者的onError()中获取信息)
return Observable.error(new Throwable("重试次数已超过设置次数 = " +currentRetryCount + ",不再重试"));
}
}
// 若发生的异常不属于I/O异常,则不重试
// 通过返回的Observable发送的事件 = Error事件 实现(可在观察者的onError()中获取信息)
else{
return Observable.error(new Throwable("发生了非网络异常(非I/O异常)"));
}
}
});
}
}).subscribeOn(Schedulers.io()) // 切换到IO线程进行网络请求
.observeOn(AndroidSchedulers.mainThread()) // 切换回到主线程 处理请求结果
.subscribe(new Observer<Translation>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Translation result) {
// 通知界面显示结果
callback.onSuccess(result);
}
@Override
public void onError(Throwable e) {
// 通知界面请求失败
callback.onError(e);
}
@Override
public void onComplete() {
}
});
}
}
/**
* 与Presenter层交互的接口
*/
public interface OnResultCallback {
// 请求成功
void onSuccess(Translation translation);
// 尝试重连
void onRetryed(int count);
// 请求失败
void onError(Throwable throwable);
}
Presenter
很简单,View和Model层的衔接,没啥好说的
public interface IMvpPresenter {
void getTranslation(String keyword);
}
public class MvpPresenterImpl implements IMvpPresenter {
private static final String TAG = MvpPresenterImpl.class.getSimpleName();
private IMvpModel model;
private IView view;
public MvpPresenterImpl(IView view) {
this.view = view;
this.model = new MvpModelImpl();
}
@Override
public void getTranslation(String keyword) {
model.getTranslation(keyword, new OnResultCallback() {
@Override
public void onSuccess(Translation translation) {
view.showResult(translation);
}
@Override
public void onRetryed(int count) {
Log.d(TAG, "onRetryed: 重试了" + count + "次了");
view.showProgress(true);
}
@Override
public void onError(Throwable throwable) {
Log.e(TAG, "onError: " + throwable.getMessage() );
view.showError(throwable);
}
});
}
}
View
public interface IView {
void showResult(Translation result);
void showError(Throwable throwable);
void showProgress(boolean isShow);
}
public class MvpActivity extends AppCompatActivity implements IView, View.OnClickListener {
private static final String TAG = MvpActivity.class.getSimpleName();
private IMvpPresenter presenter;
private Button testBt;
private EditText contextEdit;
private TextView tv_result;
private ProgressBar progressBar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvp);
initData();
initView();
}
@SuppressLint("HandlerLeak")
private void initData() {
presenter = new MvpPresenterImpl(this);
}
private void initView() {
testBt = findViewById(R.id.bt_test);
testBt.setOnClickListener(this);
contextEdit = findViewById(R.id.edit_context);
tv_result = findViewById(R.id.tv_result);
progressBar = findViewById(R.id.progress_bar);
}
@Override
public void showResult(Translation result) {
tv_result.setText("翻译结果 : " + result.getTranslateResult().get(0).get(0).getTgt());
showProgress(false);
}
@Override
public void showError(Throwable throwable) {
tv_result.setText("获取翻译结果失败,请检查网络是否连接正常!");
showProgress(false);
}
@Override
public void showProgress(boolean isShow) {
progressBar.setVisibility(isShow ? View.VISIBLE : View.GONE);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bt_test:
presenter.getTranslation(contextEdit.getText().toString());
break;
}
}
}
布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.skydianshi.mvp.view.MvpActivity">
<Button
android:id="@+id/bt_test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始翻译"/>
<EditText
android:id="@+id/edit_context"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请在此处输入要翻译的文本"
android:layout_marginTop="20dp"/>
<TextView
android:id="@+id/tv_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="翻译结果:"
android:textSize="24sp"
android:layout_marginTop="20dp"/>
<ProgressBar
android:id="@+id/progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:indeterminate="false"
android:visibility="gone"/>
</LinearLayout>
Retrofit
Retrofit的请求接口,跟上面讲Retrofit的时候讲的差不多
public interface IGetRequest {
@GET("translate?doctype=json&type=AUTO")
Observable<Translation> getResult(@Query("i") String i);
}
Retrofit工厂类
public class RetrofitFactory {
private static RetrofitFactory retrofitFactory;
public static RetrofitFactory getInstance() {
if (retrofitFactory == null) {
synchronized (RetrofitFactory.class) {
if (retrofitFactory == null) {
retrofitFactory = new RetrofitFactory();
}
}
}
return retrofitFactory;
}
public Retrofit createRetrofit(String url) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
}
总结
好了,至此本文基本结束了,总结一下,总共讲了以下几点:
- RxJava的基本使用
- Retrofit的基本使用
- MVP+RxJava+Retrofit的简单案例
之前项目中用的都是MVVM的架构,这次改用MVP来结合还有点不适应,需要定义的接口比较多,但总体感觉逻辑还是清晰一些的,由于不熟悉,文中定有诸多错误,但从实现功能的角度上来看算是完成了最初的设想,适合初学者速成,但要精通还需很多的沉淀。但从目前主流应用来看,主要的应用场景也就是本文所说的网络请求,因此把网络请求这方面理通理顺,应对普通的开发应该还是足够的,希望本文能对你有所帮助。
也希望大佬能不吝赐教文中的有误之处,感谢!
最后看一下demo的效果吧!