Retrofit与RXJava整合
Retrofit 除了提供了傳統(tǒng)的 Callback 形式的 API,還有 RxJava 版本的 Observable 形式 API。下面我用對比的方式來介紹 Retrofit 的 RxJava 版 API 和傳統(tǒng)版本的區(qū)別。
以獲取一個 User 對象的接口作為例子。使用Retrofit 的傳統(tǒng) API,你可以用這樣的方式來定義請求:
@GET("/user") public void getUser(@Query("userId") String userId, Callback<User> callback);在程序的構(gòu)建過程中, Retrofit 會把自動把方法實現(xiàn)并生成代碼,然后開發(fā)者就可以利用下面的方法來獲取特定用戶并處理響應:
getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...} };而使用 RxJava 形式的 API,定義同樣的請求是這樣的:
@GET("/user") public Observable<User> getUser(@Query("userId") String userId);使用的時候是這樣的:
getUser(userId).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});看到區(qū)別了嗎?
當 RxJava 形式的時候,Retrofit 把請求封裝進 Observable ,在請求結(jié)束后調(diào)用 onNext() 或在請求失敗后調(diào)用 onError()。
對比來看, Callback 形式和 Observable 形式長得不太一樣,但本質(zhì)都差不多,而且在細節(jié)上 Observable 形式似乎還比 Callback 形式要差點。那 Retrofit 為什么還要提供 RxJava 的支持呢?
因為它好用啊!從這個例子看不出來是因為這只是最簡單的情況。而一旦情景復雜起來, Callback 形式馬上就會開始讓人頭疼。比如:
假設(shè)這么一種情況:你的程序取到的 User 并不應該直接顯示,而是需要先與數(shù)據(jù)庫中的數(shù)據(jù)進行比對和修正后再顯示。使用 Callback 方式大概可以這么寫:
getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {processUser(user); // 嘗試修正 User 數(shù)據(jù)userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...} };有問題嗎?
很簡便,但不要這樣做。為什么?因為這樣做會影響性能。數(shù)據(jù)庫的操作很重,一次讀寫操作花費 10~20ms 是很常見的,這樣的耗時很容易造成界面的卡頓。所以通常情況下,如果可以的話一定要避免在主線程中處理數(shù)據(jù)庫。所以為了提升性能,這段代碼可以優(yōu)化一下:
getUser(userId, new Callback<User>() {@Overridepublic void success(User user) {new Thread() {@Overridepublic void run() {processUser(user); // 嘗試修正 User 數(shù)據(jù)runOnUiThread(new Runnable() { // 切回 UI 線程@Overridepublic void run() {userView.setUser(user);}});}).start();}@Overridepublic void failure(RetrofitError error) {// Error handling...} };性能問題解決,但……這代碼實在是太亂了,迷之縮進啊!雜亂的代碼往往不僅僅是美觀問題,因為代碼越亂往往就越難讀懂,而如果項目中充斥著雜亂的代碼,無疑會降低代碼的可讀性,造成團隊開發(fā)效率的降低和出錯率的升高。
這時候,如果用 RxJava 的形式,就好辦多了。 RxJava 形式的代碼是這樣的:
getUser(userId).doOnNext(new Action1<User>() {@Overridepublic void call(User user) {processUser(user);}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});其中
doOnNext()的執(zhí)行在onNext()之前,對數(shù)據(jù)進行相關(guān)處理。doOnNext在哪一個線程處理,暫時不明。
參考鏈接
RxJava操作符doOnNext - 享受技術(shù)帶來的快樂! - 博客頻道 - CSDN.NET
Rxjava中的doOnNext的作用和在哪里執(zhí)行 - u010746364的博客 - 博客頻道 - CSDN.NET
后臺代碼和前臺代碼全都寫在一條鏈中,明顯清晰了很多。
再舉一個例子:假設(shè) /user 接口并不能直接訪問,而需要填入一個在線獲取的 token ,代碼應該怎么寫?
Callback 方式,可以使用嵌套的 Callback:
@GET("/token") public void getToken(Callback<String> callback);@GET("/user") public void getUser(@Query("token") String token, @Query("userId") String userId, Callback<User> callback);...getToken(new Callback<String>() {@Overridepublic void success(String token) {getUser(token, userId, new Callback<User>() {@Overridepublic void success(User user) {userView.setUser(user);}@Overridepublic void failure(RetrofitError error) {// Error handling...}};}@Overridepublic void failure(RetrofitError error) {// Error handling...} });倒是沒有什么性能問題,可是迷之縮進毀一生,你懂我也懂,做過大項目的人應該更懂。
而使用 RxJava 的話,代碼是這樣的:
@GET("/token") public Observable<String> getToken();@GET("/user") public Observable<User> getUser(@Query("token") String token, @Query("userId") String userId);...getToken().flatMap(new Func1<String, Observable<User>>() {@Overridepublic Observable<User> onNext(String token) {return getUser(token, userId);}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Observer<User>() {@Overridepublic void onNext(User user) {userView.setUser(user);}@Overridepublic void onCompleted() {}@Overridepublic void onError(Throwable error) {// Error handling...}});用一個 flatMap() 就搞定了邏輯,依然是一條鏈。看著就很爽,是吧?
RxJava配合Retrofit2.0使用
新的Retrofit2.0簡直就是設(shè)計模式的教科書典范,同時對Rx的支持也更加友好,本例子為查詢ip獲取地理信息,并過濾掉失敗信息
//使用Rxjava配合Retrofit解析json數(shù)據(jù),注意這里全是電腦運行的,沒有分開線程訂閱 public static void main(String[] args) throws Exception{ OkHttpClient client = new OkHttpClient(); client.interceptors().add(new LoggingInterceptor());//log for okhttpRetrofit retrofit = new Retrofit.Builder().baseUrl(IPService.END).client(client).addConverterFactory(GsonConverterFactory.create())//對Response進行adapter轉(zhuǎn)換.addCallAdapterFactory(RxJavaCallAdapterFactory.create())//對轉(zhuǎn)換后的數(shù)據(jù)進行再包裝.build();retrofit.create(IPService.class)//動態(tài)代理生成class//直接操作json數(shù)據(jù),這里可不是一個好的習慣,真正應該是DTO對象的.getIPInfo("58.19.239.11").filter(jsonObject -> jsonObject.get("code").getAsInt()==0)//轉(zhuǎn)換數(shù)據(jù)類型.map(jsonObject1 -> jsonObject1.get("data"))//輸出結(jié)果.subscribe(System.out::println); }//retrofit定義的接口 interface IPService {String END = "http://ip.taobao.com";//建議寫成dto對象,博主只是為了演示filter就把這里JsonObject了@GET("/service/getIpInfo.php") Observable<JsonObject> getIPInfo(@Query("ip") String ip); }/** * Retrofit2.0已經(jīng)把網(wǎng)絡部分剝離了,所以需要自己實現(xiàn)Log */ static class LoggingInterceptor implements Interceptor { @Override public Response intercept(Chain chain) throws IOException {Request request = chain.request();long t1 = System.nanoTime();System.out.println(String.format("Sending request %s on %s%n%s", request.url(), chain.connection(),request.headers()));Response response = chain.proceed(request);long t2 = System.nanoTime();System.out.println(String.format("Received response for %s in %.1fms%n%s", response.request().url(),(t2 - t1) / 1e6d, response.headers()));return response; }源代碼
rengwuxian RxJava Samples
參考鏈接
給 Android 開發(fā)者的 RxJava 詳解
函數(shù)式編程RxJava操作實例 - 簡書
總結(jié)
以上是生活随笔為你收集整理的Retrofit与RXJava整合的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python实现简单爬虫抓取图片
- 下一篇: 指针%p输出的一些认识