前言
我们在开发过程中经常会碰到一个页面需要请求多个接口然后刷新界面数据,当然做这种需求的解决方式有很多,但是都不是很好 比如:
- 后台更改接口,所有数据做成一个接口
后台系统一般来说比较成熟,而且开发进度在前端前面,一般不会为了前端做出很大的改变,并且需求是一只加,谁也不清楚,一个界面需要的数据到底需要多少,包括后台 - 一个接口接着一个请求,请求成功或者失败做其他接口的请求
这样子当然可以,但是逻辑上就复杂了并且以后的维护非常麻烦,比如 A B C三个接口,在A请求成功后请求B,B请求成功后请求C,这样的嵌套请求非常不优雅 - 当然也可以三个并排请求
什么也不管比如一进入页面三个ABC接口都放在初始方法中,但是这样有些风险,因为接口请求都是异步的,谁也琢磨不到三个接口的先后顺序,万一 前面接口的成功与否关系到后面接口就会报错,并且如果需求是有先后顺序的请求呢?所以这种是最不推荐的,但是也是平常非常不容易忽略的
优雅的解决方案
并行执行:merge() / mergeArray()
作用:组合多个被观察者一起发送数据,合并后 按时间线并行执行
并行执行:指的是多个接口请求同时执行(类似物理中学过的电路并联)
二者区别:组合被观察者的数量,即merge()组合被观察者数量≤4个,而mergeArray()则可>4个。
串行执行:concat() / concatArray()
作用:组合多个被观察者一起发送数据,合并后 按发送顺序串行(后一个必须等前一个执行完之后)执行
串行执行:指的是后一个接口必须等前一个接口执行完成后才开始执行(类似物理中学过的电路串联)
二者区别:组合被观察者的数量,即concat()组合被观察者数量≤4个,而concatArray()则可>4个。
concatDelayError() / mergeDelayError()
背景:在使用上面的merge和concat操作符时,如果其中某个接口请求出现问题,即发出了onError事件,则会立即终止其他被观察者继续发送事件,也就是说如果中间某个接口请求出了问题,那么会导致后面的接口也不会正常获取到数据,即使后面的接口没有任何问题。
解决方案:使用上面提到的xxxxDelayError操作符,即使中间某个接口出现问题也不会影响其他接口的正常请求。mergeDelayError的原始observable出现onError时,错误通知会被保留,直到所有数据发射完毕后才执行onError。如果有多个原始observable出现了onError,这些onError通知会被合并成一个CompositeException ,保留在它的 List exceptions异常列表里。如果只有一个原始observable出现了onError,则会直接使用这个onError通知,而不会生成CompositeException。
这样如果想对原始observable的异常原因有针对性第处理,就要重写最后subscriber的onError方法,区分两种情况:
public void onError(Throwable e) {
if (e instanceof CompositeException) {
CompositeException compositeException = (CompositeException) e;
e = compositeException.getExceptions().get(0);
}
super.onError(e);
}
使用案例:(OkGo+RxJava2+MVP架构,具体参见源码:https://github.com/gpf0205/gpfokgomvp)
public class ApiService {
/**
* 首页Banner
*
* @GET("http://wanandroid.com/banner/json")
*/
public static Observable<ResponseData<List<BannerBean>>> getBannerData() {
return OkGo.<ResponseData<List<BannerBean>>>get(ApiConst.HOME_BANNER)
.cacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)
.converter(new JsonConvert<ResponseData<List<BannerBean>>>() {
})
.adapt(new ObservableBody<ResponseData<List<BannerBean>>>());
}
public static Observable<ResponseData<List<PersonBean>>> getPersonData() {
return OkGo.<ResponseData<List<PersonBean>>>get(ApiConst.HOME_BANNER)
.cacheMode(CacheMode.FIRST_CACHE_THEN_REQUEST)
.converter(new JsonConvert<ResponseData<List<PersonBean>>>() {
})
.adapt(new ObservableBody<ResponseData<List<PersonBean>>>());
}
/**
* 请求合并的方法,merge<=4
* @return
*/
public static Observable<ResponseData<? extends List<? extends Serializable>>> getAllData() {
return Observable.merge(getBannerData(),getPersonData());
}
/**
* 请求合并的方法,大于4个时使用mergeArray
* @return
*/
public static Observable<ResponseData<? extends List<? extends Serializable>>> getAllData1() {
return Observable.mergeArray(getBannerData(),getPersonData(),getPersonData(),getPersonData(),getPersonData());
}
/**
* 请求合并的方法,异常处理
* @return
*/
public static Observable<ResponseData<? extends List<? extends Serializable>>> getAllData2() {
return Observable.mergeArrayDelayError(getBannerData(),getPersonData());
}
/**
* 请求合并的方法
* @return
*/
public static Observable<ResponseData<? extends List<? extends Serializable>>> getAllData3() {
return Observable.concat(getBannerData(),getPersonData());
}
/**
* 请求合并的方法
* @return
*/
public static Observable<ResponseData<? extends List<? extends Serializable>>> getAllData4() {
return Observable.concatArray(getBannerData(),getPersonData(),getPersonData(),getPersonData(),getPersonData());
}
/**
* 请求合并的方法
* @return
*/
public static Observable<ResponseData<? extends List<? extends Serializable>>> getAllData5() {
return Observable.concatArrayDelayError(getBannerData(),getPersonData(),getPersonData(),getPersonData(),getPersonData());
}
}