RxJava + Retrofit完成網路請求

yangxi_001發表於2017-05-17

RxJava + Retrofit

前言

本文基於RxJava、Retrofit的使用,若是對RxJava或Retrofit還不瞭解的簡友可以先了解RxJava、Retrofit的用法再來看這篇文章。
在這片文章之前分別單獨介紹過Rxjava以及Retrofit的使用:
Android Retrofit 2.0 的使用
Android RxJava的使用(一)基本用法
(以及後面的幾篇,就不一一列出了)

使用

在瞭解了RxJava和Retrofit分別的用法後,RxJava、Retrofit的搭配使用也就不再話下了。
先看看使用Retrofit完成一次網路請求是怎樣的

  • 單獨使用Retrofit
    1、先寫一個service

    interface MyService {
      @GET("user/login" )
      Call<UserInfo> login(
              @Query("username") String username,
              @Query("password") String password
      );
    }

    2、獲取Call執行網路請求

          Retrofit retrofit = new Retrofit.Builder()
                  .addConverterFactory(GsonConverterFactory.create())
                  .baseUrl(BASE_URL)
                  .build();
          MyService service = retrofit.create(MyService.class);
    
          Call<UserInfo> call = service.login("1111", "ssss");
          call.enqueue(new Callback<UserInfo>() {
              @Override
              public void onResponse(Call<UserInfo> call, Response<UserInfo> response) {
                  //請求成功操作
              }
              @Override
              public void onFailure(Call<UserInfo> call, Throwable t) {
                  //請求失敗操作
              }
          });

    以上是Retrofit單獨使用時的做法。那Retrofit與RxJava結合是怎樣使用的?下面就來說說這篇文章的重點。

  • RxJava + Retrofit完成網路請求
    1、新增依賴。前四個分別是RxJava、RxAndroid、Retrofit以及Gson的庫,最後那個才是新加入的,RxJava + Retrofit的使用需要用到最後那個包。

      compile 'io.reactivex:rxjava:x.y.z'
      compile 'io.reactivex:rxandroid:1.0.1'
      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'

    注意:最後三個包的版本號必須一樣,這裡用的是2.0.2。
    2、寫一個登入的service

    interface MyService {
      @GET("user/login" )
      Observable<UserInfo> login(
              @Query("username") String username,
              @Query("password") String password
      );
    }

    相比之前的service,這裡getNews方法的返回值是Observable型別。Observable...是不是覺得很熟悉,這貨不就是之前在RxJava使用到的被監聽者?
    3、使用Observable完成一個網路請求,登入成功後儲存資料到本地。

          Retrofit retrofit = new Retrofit.Builder()
                .addConverterFactory(GsonConverterFactory.create())
                .addCallAdapterFactory(RxJavaCallAdapterFactory.create())//新的配置
                .baseUrl(BASE_URL)
                .build();
          MyService service = retrofit.create(MyService.class);
    
          service.login(phone, password)               //獲取Observable物件
                  .subscribeOn(Schedulers.newThread())//請求在新的執行緒中執行
                  .observeOn(Schedulers.io())         //請求完成後在io執行緒中執行
                  .doOnNext(new Action1<UserInfo>() {
                      @Override
                      public void call(UserInfo userInfo) {
                          saveUserInfo(userInfo);//儲存使用者資訊到本地
                      }
                  })
                  .observeOn(AndroidSchedulers.mainThread())//最後在主執行緒中執行
                  .subscribe(new Subscriber<UserInfo>() {
                      @Override
                      public void onCompleted() {
    
                      }
    
                      @Override
                      public void onError(Throwable e) {
                          //請求失敗
                      }
    
                      @Override
                      public void onNext(UserInfo userInfo) {
                          //請求成功
                      }
                  });

    RxJava + Retrofit 形式的時候,Retrofit 把請求封裝進 Observable ,在請求結束後呼叫 onNext() 或在請求失敗後呼叫 onError()。
    可以看到,呼叫了service的login方法後得到Observable物件,在新的執行緒中執行網路請求,請求成功後切換到io執行緒執行儲存使用者資訊的動作,最後再切換到主執行緒執行請求失敗onError()、請求成功onNext()。整體的邏輯十分清晰都在一條鏈中,就算還有別的要求還可以往裡面新增,絲毫不影響程式碼的簡潔。(終於舉了一個有實際意義的例子)

    注意:retrofit的初始化加了一行程式碼

    addCallAdapterFactory(RxJavaCallAdapterFactory.create())
  • RxJava + Retrofit 進階
    在上面舉到登入後儲存使用者資訊的例子,其實在做專案的時候,往往在登入後得到的並不是使用者資訊。一般登入後會得到token,然後根據token去獲取使用者的資訊。他們的步驟是這樣的:
    1、登入
    2、獲取使用者資訊(前提:登入成功)
    可以看得出來,這是一個巢狀的結構...巢狀啊!!!天吶,最怕巢狀的結構了。
    使用RxJava + Retrofit來完成這樣的請求(借用拋物線的例子,稍微做了點改動)

    //登入,獲取token
    @GET("/login")
    public Observable<String> login(   
      @Query("username") String username,
      @Query("password") String password);
    //根據token獲取使用者資訊
    @GET("/user")
    public Observable<User> getUser(
      @Query("token") String token);
    //..................................
    service.login("11111", "22222")
      .flatMap(new Func1<String, Observable<User>>() {  //得到token後獲取使用者資訊
          @Override
          public Observable<User> onNext(String token) {
              return service.getUser(token);
          })
      .subscribeOn(Schedulers.newThread())//請求在新的執行緒中執行請求
      .observeOn(Schedulers.io())         //請求完成後在io執行緒中執行
      .doOnNext(new Action1<User>() {      //儲存使用者資訊到本地
           @Override
           public void call(User userInfo) {
               saveUserInfo(userInfo);
           }
       })
      .observeOn(AndroidSchedulers.mainThread())//在主執行緒中執行
      .subscribe(new Observer<User>() {
          @Override
          public void onNext(User user) {
              //完成一次完整的登入請求
              userView.setUser(user);
          }
    
          @Override
          public void onCompleted() {
    
          }
    
          @Override
          public void onError(Throwable error) {
              //請求失敗
          }
      });

    通過一個flatMap()輕鬆完成一次巢狀的請求,而且邏輯十分清晰。so easy~~~

小結

RxJava的實用性從上面的兩個例子慢慢體現了出來,邏輯越是複雜,RxJava的優勢就越明顯。RxJava的使用就暫時介紹到這裡吧,使用過程中遇到好用的再出來跟大家分享。

以上有錯誤之處感謝指出

參考:給 Android 開發者的 RxJava 詳解

相關文章