Android RxJava + Retrofit 的實際應用場景
介紹
關于 RxJava Retrofit 很多篇文章都有詳細的說明,在這里我想分享一個具體的使用案例,在我的開源項目 就看天氣 里的實際應用。也希望跟大家探討如何優雅的使用。
前提
需要知道什么是 RxJava
這里推薦下 扔物線寫的 給 Android 開發者的 RxJava 詳解
再感謝 RxJava 與 Retrofit 結合的最佳實踐 這篇滿滿的干貨。
實戰
準備
項目中用到的依賴:
compile 'io.reactivex:rxjava:1.1.0' compile 'io.reactivex:rxandroid:1.1.0' compile 'com.google.code.gson:gson:2.4' compile 'com.squareup.retrofit2:retrofit:2.0.2' compile 'com.squareup.retrofit2:converter-gson:2.0.2' compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2' compile 'com.squareup.okhttp3:okhttp:3.0.1' compile 'com.squareup.okhttp3:logging-interceptor:3.0.1' compile 'com.squareup.okio:okio:1.6.0'
因為要用到網絡,所以千萬別忘記了這個權限。
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
組件
Rx 封裝的工具
使用 compose 操作符
compose() 里接收一個 Transformer 對象, Transformer 繼承自 Func1<Observable<T>, Observable<R>> ,可以通過它將一種類型的 Observable 轉換成另一種類型的 Observable 。
RxSchedulerHelper
封裝 Rx 線程相關操作
public static <T> Observable.Transformer<T, T> rxSchedulerHelper() {
return tObservable -> tObservable.subscribeOn(Schedulers.io())
.unsubscribeOn(AndroidSchedulers.mainThread())
.observeOn(AndroidSchedulers.mainThread());
}
handleResult
封裝 API 請求后統一處理
public static <T> Observable.Transformer<Result<T>, T> handleResult() {
return resultObservable -> resultObservable.flatMap(tResult -> {
if (tResult.code == 1) {
return createData(tResult.data);
} else {
return Observable.error(new ApiException(tResult.code));
}
});
}
RetrofitSingleton
自己封裝了下 Retrofit 。可以學習下 小艾的方式 。
自己將請求是寫在該類,使用者只需要關心如何處理拿到的數據和相應的 UI 操作。
public Observable<Weather> fetchWeather(String city) {
return apiService.mWeatherAPI(city, C.KEY)
.filter(weatherAPI -> weatherAPI.mHeWeatherDataService30s.get(0).status.equals("ok"))
.map(weatherAPI -> weatherAPI.mHeWeatherDataService30s.get(0))
.compose(RxUtils.rxSchedulerHelper());
}
public Observable<VersionAPI> fetchVersion() {
return apiService.mVersionAPI(C.API_TOKEN).compose(RxUtils.rxSchedulerHelper());
}
</pre>
使用
將 網絡拉取 和 讀取緩存 用 Rx 結合。
這里就要使用 concat 操作符, 官方解釋 .
首先看看獲取網絡是如何寫的:
private Observable<Weather> fetchDataByNetWork() {
String cityName = Util.replaceCity(mSetting.getCityName());
return RetrofitSingleton.getInstance()
.fetchWeather(cityName)
.onErrorReturn(throwable -> {
PLog.e(throwable.getMessage());
return null;
});
}
這里的 onErrorReturn 待會兒說。
再來看看讀取緩存的代碼:
private Observable<Weather> fetchDataByCache() {
return Observable.defer(() -> {
Weather weather = (Weather) aCache.getAsObject(C.WEATHER_CACHE);
return Observable.just(weather);
});
}
然后我們將他們連接起來:
private void load() {
Observable.concat(fetchDataByNetWork(), fetchDataByCache())
.first(weather -> weather != null)
.doOnError(throwable -> {
mErroImageView.setVisibility(View.VISIBLE);
mRecyclerView.setVisibility(View.GONE);
})
.doOnNext(weather -> {
mErroImageView.setVisibility(View.GONE);
mRecyclerView.setVisibility(View.VISIBLE);
})
.doOnTerminate(() -> {
mRefreshLayout.setRefreshing(false);
mProgressBar.setVisibility(View.GONE);
})
.subscribe(observer);
}
concat + first 連接和過濾的操作實現了,網絡+緩存的邏輯。
剛剛為什么說要在網絡代碼那里使用 onErrorReturn 呢?
如果不寫,網絡發生異常的話,整個流就會直接走 onError ,不會執行到讀取緩存的流。
結語
Rx 的各種操作符的不同組合就可以實現不同的效果。本身 Rx 封裝已經足夠好了,我們加工的時候一定要想到是否破壞了他本身的優雅。
因為 Rx 是一種數據流鏈式結構的編程思想,我們在封裝時應該不能打斷其鏈式結構。
歡迎互相討論和探討 :)

來自: http://imxie.cc/2016/05/24/RxJava-Retrofit-的實際應用場景/