煮 Retrofit 論 RxJava(二)

為什么要用Rxjava?沒看出Rxjava到底解決了我們什么問題。一門技術或框架只有解決了實際問題,我們才能體會它的美妙,所以我們直面開發中的真實場景。

先來回顧下上篇我們使用Retrofit請求時的方法:

 @GET("top250")
 Call<MovieEntity> getTopMovie(@Query("start") int start, @Query("count") int count);

 getTopMovie(0, 10).enqueue(new Callback<MovieEntity>() {
      @Override
      public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
         resultTV.setText(response.body().toString());
      }

      @Override
      public void onFailure(Call<MovieEntity> call, Throwable t) {
         resultTV.setText(t.getMessage());
      }
 });

現在我們使情景復雜起來,比如獲取到MovieEntity后,需要先跟數據庫中的數據對比后,再進行顯示,可以這樣寫:

 getTopMovie(0, 10).enqueue(new Callback<MovieEntity>() {
      @Override
      public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
         /** 嘗試比較數據并更新 **/
         processData(response.body);
         resultTV.setText(response.body().toString());
      }

      @Override
      public void onFailure(Call<MovieEntity> call, Throwable t) {
         resultTV.setText(t.getMessage());
      }
 });

但是把數據庫的操作直接放在主線程里,會造成界面卡頓,為了提升性能,我們把它放到子線程里:

 getTopMovie(0, 10).enqueue(new Callback<MovieEntity>() {
      @Override
      public void onResponse(Call<MovieEntity> call, Response<MovieEntity> response) {
         new Thread() {
            @Override
            public void run() {
                /** 嘗試比較數據并更新 **/
                processData(response.body);
                /** 切回主線程 **/
                runOnUiThread(new Runnable() { 
                    @Override
                    public void run() {
                        resultTV.setText(response.body().toString());
                    }
                });
            }).start();       
      }

      @Override
      public void onFailure(Call<MovieEntity> call, Throwable t) {
         resultTV.setText(t.getMessage());
      }
 });

也許你早就對這種雜亂的流程代碼看不順眼了吧,忍了好久終于到今天~,那不妨試試到手的Rxjava:

getTopMovie(start, count)
     .subscribeOn(Schedulers.io())
     /** doOnNext()允許我們在執行onNext()方法之前做一些額外的事情;
       * 這里它是運行在Schedulers.io,所以我們可以訪問數據庫;
       * 它和onNext()方法是同步操作,即執行完doOnNext()方法后才去執行onNext()方法。
      **/
     .doOnNext(new Action1<HttpResult<List<Subject>>>() {
          @Override
          public void call(HttpResult<List<Subject>> subjects) {
               /** 嘗試比較數據并修復數據 **/
               processData(subjects);
          }
     })
     .observeOn(AndroidSchedulers.mainThread())
     .subscribe(new Subscriber<HttpResult<List<Subject>>>() {
          @Override
          public void onNext(HttpResult<List<Subject>> subjects) {
          }
          @Override
          public void onCompleted() {
          }
          @Override
          public void onError(Throwable e) {
          }
     });

這樣一來,我們的代碼邏輯是不是清晰多了。如果我們的需求是請求完數據,存放到數據庫,并顯示在UI上,那么上面doOnNext()(關于doOnNext()的測試)和onNext()方法的同步就顯然不適用了,不過我們可以這樣來修改:

.doOnNext(new Action1<HttpResult<List<Subject>>>() {
     @Override
     public void call(HttpResult<List<Subject>> subjects) {
         /** 這里我們使用Schedulers.io()創建非阻塞的版本,
         這樣saveData()和onNext()就實現了異步操作 **/
         Schedulers.io().createWorker().schedule(new Action0() {
            @Override
            public void call() {
                 /** 這里我們把數據存到數據庫里 **/
                 saveData(subjects);
            }
         });
     }
})

再來看一個同步等待的場景:假設獲取電影top250的接口不能直接訪問,需要填入一個在線獲取的 token,此時該怎么辦?

@GET("/token")
public void getToken(Callback<String> callback);

@GET("top250")
Call<MovieEntity> getTopMovie(@Query("token") String token, @Query("start") int start, @Query("count") int count);

/** 先獲取token **/
getToken(new Callback<String>() {
    @Override
    public void onResponse(String token) {
        /** 成功后再獲取電影列表數據 **/
        getTopMovie(token, 0, 10, new Callback<MovieEntity>() {
            @Override
            public void onResponse(MovieEntity response) {
                resultTV.setText(response.toString());
            }
            @Override
            public void onFailure(RetrofitError error) {
            }
        };
    }

    @Override
    public void onFailure(RetrofitError error) {
    }
});

又是嵌套式的代碼結構,還是不爽不爽。

/** 首先調用getToken() **/
 getToken()  
     /** flatMap()允許我們干預事件流程并返回一個Observable,即轉換為其他事件 **/
    .flatMap(new Func1<String, Observable<HttpResult<List<Subject>>>>() {
        @Override
        public Observable<HttpResult<List<Subject>>> onNext(String token) {
            /** 然后調用getTopMovie() **/
            return getTopMovie(token, 0, 10);
        })
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(new Subscriber<HttpResult<List<Subject>>>() {
          @Override
          public void onNext(HttpResult<List<Subject>> subjects) {
          }
          @Override
          public void onCompleted() {
          }
          @Override
          public void onError(Throwable e) {
          }
     });

以上使用flatMap即用到了Rxjava的 變換 概念,所謂變換,就是將事件序列中的對象或整個序列進行加工處理,轉換成不同的事件或事件序列。通常可以使用map,flatMap,lift等方法來處理變換。

剛開始可能會覺得Rxjava的封裝比較抽象,使用起來比較生澀,但通過以上情景的討論,我們能夠看出Rxjava在代碼結構上本質的簡潔,通過練習多多上手,最終用在項目上才是學習、使用它的最好方式。

轉載請標明出處:http://www.lxweimin.com/p/3cd9bf183926

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容