这篇文章的由来
目前项目中引入了RxJava
,而我在其他项目里分别使用过Retrofit
以及Retrofit
+ RxJava
。以自己的感受而言,RxJava
确实很强大,而且对于编码效率和代码简洁性有不小的提升,所以简单对比一下两者的区别。本文默认读者已熟悉RxJava的基本Api以及使用场景,若非如此,则参考该文章:http://gank.io/post/560e15be2dca930e00da1083。
干货
基本使用
在目前的项目里,使用Retrofit
与Retrofit
+ RxJava
的场景几乎类似,代码上有一点区别:
- 在
StickerServerApi
中写下接口方法:
// 使用Retrofit
@GET("path")
Call apiName(@QueryMap Map params);
// 使用Retrofit + RxJava
@GET("path")
Observable apiName(@QueryMap Map params);
- 在
WebService
中,调用StickerServerApi
中的方法:
// 使用Retrofit
@MainThread
public void requestApi(Callback callback) {
Map params = getParamsPacker().pack();
Call call = mStickerServerApi.apiName(params);
call.enqueue(callback);
}
// 使用Retrofit + RxJava
public Observable requestApi() {
Map params = getParamsPacker().pack();
return mStickerServerApi.apiName(params);
}
- 在
Repository
中,调用WebService
中的方法,并处理响应逻辑:
// 使用Retrofit
public LiveData> requestApi() {
getWebService().requestApi(new Callback() {
@Override
public void onResponse(Call call, Response response) {
mLiveData.setValue(Resource.success(response.body());
}
@Override
public void onFailure(Call call, Throwable t) {
mLiveData.setValue(Resource.error(t.message);
}
});
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData> requestApi() {
getWebService().requestApi()
// 在子线程调用接口
.subscribeOn(Schedulers.io())
// 在主线程调用回调方法
.observeOn(AndroidSchedulers.mainThread())
// subscribe方法针对不同的参数有很多的重载方法
// 下文传入Observer对象的重载方法是相对回调最多的,所以看起来似乎比上面的代码更复杂
// 实际使用中可以使用其他重载方法以传入更为简单的接口对象
.subscribe(new Observer>>() {
@Override
public void onSubscribe(Disposable d) {
// 在订阅时触发,这里可以不作处理
}
@Override
public void onNext(T t) {
// 相当于onResponse,和onError互斥触发
mLiveData.setValue(Resource.success(t);
}
@Override
public void onError(Throwable e) {
// onFail,和onNext互斥触发
mLiveData.setValue(Resource.error(t.message);
}
@Override
public void onComplete() {
// 在onNext或者onError后触发,可以不作处理
}
})
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
- 在
View
层进行liveData
的订阅,处理相应的UI变化。这部分的代码没有区别,不再赘述。
复杂情景中的使用
这部分与基本使用中的代码区别在于Repository
中的逻辑,所以只贴出Repository
中的代码。
- 接口的循环调用。某些场景下,需要先请求接口1获取响应数据,并作为接口2的请求参数,而最终的逻辑需要在接口2的响应方法中执行。在项目中也有这样的情景,比如上传资源文件到阿里云后台,然后将地址发送给服务器。
// 使用Retrofit
public LiveData> requestApi() {
getWebService().requestApi1(new Callback() {
@Override
public void onResponse(Call call, Response response) {
// api1的返回值是api2的请求参数
T t = response.body();
getWebService().requestApi2(t, new Callback() {
@Override
public void onResponse(Call call, Response response) {
mLiveData.setValue(Resource.success(response.body());
}
@Override
public void onFailure(Call call, Throwable t) {
mLiveData.setValue(Resource.error(t.message);
}
});
}
@Override
public void onFailure(Call call, Throwable t) {
mLiveData.setValue(Resource.error(t.message);
}
});
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData> requestApi() {
getWebService().requestApi1()
// 在子线程调用接口
.subscribeOn(Schedulers.io())
.flatMap(new Function>() {
@Override
public ObservableSource apply(T t) throws Exception {
// api1的返回值是api2的请求参数
return getWebService().requestApi2(t);
}
})
// 在主线程调用回调方法
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
// 在订阅时触发,这里可以不作处理
}
@Override
public void onNext(K k) {
// 相当于onResponse,和onError互斥触发
mLiveData.setValue(Resource.success(k);
}
@Override
public void onError(Throwable t) {
// onFail,和onNext互斥触发
mLiveData.setValue(Resource.error(t.message);
}
@Override
public void onComplete() {
// 在onNext或者onError后触发,可以不作处理
}
})
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
可以看到,在Retrofit
中,想要实现接口套接口的逻辑,需要两层Callback
嵌套,而如果加入了RxJava
,则只需要调用flatMap()
就可以了。前者的多层嵌套相比后者无论从开发效率还是代码可读性而言都要略逊一筹。而这只是两层嵌套,如果是多层嵌套,差距更显而易见。
- 在接收到响应数据后,进行一些异步操作。
网络请求的回调方法通常需要进行UI更新,所以一般回调方法都是在主线程中运行。而如果这时需要进行一些异步操作,比如io读取、数据库存取,代码就会比较复杂。以下以下载视频为例。
// 使用Retrofit
public LiveData> requestApi() {
getWebService().requestApi(new Callback
// 使用Retrofit + RxJava
public LiveData> requestApi() {
getWebService().requestApi()
// 在子线程调用接口
.subscribeOn(Schedulers.io())
.map(new Function, File>() {
@Override
public File apply(T t) throws Exception {
File file = new File("filePath");
// 省略写文件逻辑
...
// 返回文件
return file;
}
})
// 切换回主线程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onSubscribe(Disposable d) {
// 在订阅时触发,这里可以不作处理
}
@Override
public void onNext(File file) {
// 相当于onResponse,和onError互斥触发
// 其他逻辑
...
// liveData赋值
mLiveData.setValue(Resource.success(file);
}
@Override
public void onError(Throwable t) {
// onFail,和onNext互斥触发
mLiveData.setValue(Resource.error(t.message);
}
@Override
public void onComplete() {
// 在onNext或者onError后触发,可以不作处理
}
})
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
对比这一场景中的两部分代码,同样地,单独使用Retrofit
时,动辄两三层的缩进,以及onResponse()
方法中大量的代码,都会降低可读性和开发效率。在加入了RxJava
后,只需要一个map()
方法(还有其他有用的api,这里暂时不提),再加上RxJava
的线程调度特性,就使代码看起来简单了许多。
总结
现在很多文章都推荐使用RxJava
和Retrofit
进行网络请求框架的搭建,而且Retrofit
本身也对RxJava
进行了支持,这就足够说明加入RxJava
是有一定的意义的。而我自己的使用经验也使得我更偏向于结合RxJava
来使用Retrofit
。但这毕竟只是个工具,而且相对陌生,有一定的学习成本,并且开发效率受到熟练度的影响。但不论最终是否加入RxJava
,多了解一下也是有好处的。