這篇文章的由來
目前項(xiàng)目中引入了RxJava,而我在其他項(xiàng)目里分別使用過Retrofit以及Retrofit+ RxJava。以自己的感受而言,RxJava確實(shí)很強(qiáng)大,而且對(duì)于編碼效率和代碼簡潔性有不小的提升,所以簡單對(duì)比一下兩者的區(qū)別。本文默認(rèn)讀者已熟悉RxJava的基本Api以及使用場景,若非如此,則參考該文章:http://gank.io/post/560e15be2dca930e00da1083。
干貨
基本使用
在目前的項(xiàng)目里,使用Retrofit與Retrofit + RxJava的場景幾乎類似,代碼上有一點(diǎn)區(qū)別:
- 在
StickerServerApi中寫下接口方法:
// 使用Retrofit
@GET("path")
Call<T> apiName(@QueryMap Map<String, String> params);
// 使用Retrofit + RxJava
@GET("path")
Observable<T> apiName(@QueryMap Map<String, String> params);
- 在
WebService中,調(diào)用StickerServerApi中的方法:
// 使用Retrofit
@MainThread
public void requestApi(Callback<T> callback) {
Map<String, String> params = getParamsPacker().pack();
Call<T> call = mStickerServerApi.apiName(params);
call.enqueue(callback);
}
// 使用Retrofit + RxJava
public Observable<T> requestApi() {
Map<String, String> params = getParamsPacker().pack();
return mStickerServerApi.apiName(params);
}
- 在
Repository中,調(diào)用WebService中的方法,并處理響應(yīng)邏輯:
// 使用Retrofit
public LiveData<Resource<T>> requestApi() {
getWebService().requestApi(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
mLiveData.setValue(Resource.success(response.body());
}
@Override
public void onFailure(Call<T> call, Throwable t) {
mLiveData.setValue(Resource.error(t.message);
}
});
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData<Resource<T>> requestApi() {
getWebService().requestApi()
// 在子線程調(diào)用接口
.subscribeOn(Schedulers.io())
// 在主線程調(diào)用回調(diào)方法
.observeOn(AndroidSchedulers.mainThread())
// subscribe方法針對(duì)不同的參數(shù)有很多的重載方法
// 下文傳入Observer對(duì)象的重載方法是相對(duì)回調(diào)最多的,所以看起來似乎比上面的代碼更復(fù)雜
// 實(shí)際使用中可以使用其他重載方法以傳入更為簡單的接口對(duì)象
.subscribe(new Observer<BaseData<List<StarResponseModel>>>() {
@Override
public void onSubscribe(Disposable d) {
// 在訂閱時(shí)觸發(fā),這里可以不作處理
}
@Override
public void onNext(T t) {
// 相當(dāng)于onResponse,和onError互斥觸發(fā)
mLiveData.setValue(Resource.success(t);
}
@Override
public void onError(Throwable e) {
// onFail,和onNext互斥觸發(fā)
mLiveData.setValue(Resource.error(t.message);
}
@Override
public void onComplete() {
// 在onNext或者onError后觸發(fā),可以不作處理
}
})
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
- 在
View層進(jìn)行liveData的訂閱,處理相應(yīng)的UI變化。這部分的代碼沒有區(qū)別,不再贅述。
復(fù)雜情景中的使用
這部分與基本使用中的代碼區(qū)別在于Repository中的邏輯,所以只貼出Repository中的代碼。
- 接口的循環(huán)調(diào)用。某些場景下,需要先請(qǐng)求接口1獲取響應(yīng)數(shù)據(jù),并作為接口2的請(qǐng)求參數(shù),而最終的邏輯需要在接口2的響應(yīng)方法中執(zhí)行。在項(xiàng)目中也有這樣的情景,比如上傳資源文件到阿里云后臺(tái),然后將地址發(fā)送給服務(wù)器。
// 使用Retrofit
public LiveData<Resource<T>> requestApi() {
getWebService().requestApi1(new Callback<T>() {
@Override
public void onResponse(Call<T> call, Response<T> response) {
// api1的返回值是api2的請(qǐng)求參數(shù)
T t = response.body();
getWebService().requestApi2(t, new Callback<K>() {
@Override
public void onResponse(Call<K> call, Response<K> response) {
mLiveData.setValue(Resource.success(response.body());
}
@Override
public void onFailure(Call<K> call, Throwable t) {
mLiveData.setValue(Resource.error(t.message);
}
});
}
@Override
public void onFailure(Call<T> call, Throwable t) {
mLiveData.setValue(Resource.error(t.message);
}
});
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData<Resource<T>> requestApi() {
getWebService().requestApi1()
// 在子線程調(diào)用接口
.subscribeOn(Schedulers.io())
.flatMap(new Function<T, ObservableSource<K>>() {
@Override
public ObservableSource<K> apply(T t) throws Exception {
// api1的返回值是api2的請(qǐng)求參數(shù)
return getWebService().requestApi2(t);
}
})
// 在主線程調(diào)用回調(diào)方法
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<K>() {
@Override
public void onSubscribe(Disposable d) {
// 在訂閱時(shí)觸發(fā),這里可以不作處理
}
@Override
public void onNext(K k) {
// 相當(dāng)于onResponse,和onError互斥觸發(fā)
mLiveData.setValue(Resource.success(k);
}
@Override
public void onError(Throwable t) {
// onFail,和onNext互斥觸發(fā)
mLiveData.setValue(Resource.error(t.message);
}
@Override
public void onComplete() {
// 在onNext或者onError后觸發(fā),可以不作處理
}
})
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
可以看到,在Retrofit中,想要實(shí)現(xiàn)接口套接口的邏輯,需要兩層Callback嵌套,而如果加入了RxJava,則只需要調(diào)用flatMap()就可以了。前者的多層嵌套相比后者無論從開發(fā)效率還是代碼可讀性而言都要略遜一籌。而這只是兩層嵌套,如果是多層嵌套,差距更顯而易見。
- 在接收到響應(yīng)數(shù)據(jù)后,進(jìn)行一些異步操作。
網(wǎng)絡(luò)請(qǐng)求的回調(diào)方法通常需要進(jìn)行UI更新,所以一般回調(diào)方法都是在主線程中運(yùn)行。而如果這時(shí)需要進(jìn)行一些異步操作,比如io讀取、數(shù)據(jù)庫存取,代碼就會(huì)比較復(fù)雜。以下以下載視頻為例。
// 使用Retrofit
public LiveData<Resource<File>> requestApi() {
getWebService().requestApi(new Callback<Video>() {
@Override
public void onResponse(Call<Video> call, Response<Video> response) {
Video video = response.body();
final String url = video.url;
final Handler handler = new Handler();
new Thread() {
@Override
public void run() {
File file = new File("filePath");
// 寫文件邏輯省略
...
// 切回 UI 線程
handler.post(new Runnable() {
@Override
public void run() {
// 可能存在的其他邏輯省略
...
// liveData賦值
mLiveData.setValue(Resource.success(file))
}
});
}
}).start();
}
@Override
public void onFailure(Call<T> call, Throwable t) {
mLiveData.setValue(Resource.error(t.message);
}
});
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
// 使用Retrofit + RxJava
public LiveData<Resource<File>> requestApi() {
getWebService().requestApi()
// 在子線程調(diào)用接口
.subscribeOn(Schedulers.io())
.map(new Function<T>, File>() {
@Override
public File apply(T t) throws Exception {
File file = new File("filePath");
// 省略寫文件邏輯
...
// 返回文件
return file;
}
})
// 切換回主線程
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<File>() {
@Override
public void onSubscribe(Disposable d) {
// 在訂閱時(shí)觸發(fā),這里可以不作處理
}
@Override
public void onNext(File file) {
// 相當(dāng)于onResponse,和onError互斥觸發(fā)
// 其他邏輯
...
// liveData賦值
mLiveData.setValue(Resource.success(file);
}
@Override
public void onError(Throwable t) {
// onFail,和onNext互斥觸發(fā)
mLiveData.setValue(Resource.error(t.message);
}
@Override
public void onComplete() {
// 在onNext或者onError后觸發(fā),可以不作處理
}
})
mLiveData.setValue(Resource.loading(null));
return mLiveData;
}
對(duì)比這一場景中的兩部分代碼,同樣地,單獨(dú)使用Retrofit時(shí),動(dòng)輒兩三層的縮進(jìn),以及onResponse()方法中大量的代碼,都會(huì)降低可讀性和開發(fā)效率。在加入了RxJava后,只需要一個(gè)map()方法(還有其他有用的api,這里暫時(shí)不提),再加上RxJava的線程調(diào)度特性,就使代碼看起來簡單了許多。
總結(jié)
現(xiàn)在很多文章都推薦使用RxJava和Retrofit進(jìn)行網(wǎng)絡(luò)請(qǐng)求框架的搭建,而且Retrofit本身也對(duì)RxJava進(jìn)行了支持,這就足夠說明加入RxJava是有一定的意義的。而我自己的使用經(jīng)驗(yàn)也使得我更偏向于結(jié)合RxJava來使用Retrofit。但這畢竟只是個(gè)工具,而且相對(duì)陌生,有一定的學(xué)習(xí)成本,并且開發(fā)效率受到熟練度的影響。但不論最終是否加入RxJava,多了解一下也是有好處的。