1. 程式人生 > >RxJava和Retrofit的簡單使用

RxJava和Retrofit的簡單使用

在最近做的專案中,因為頻繁用到網路請求,所以使用了現在比較流行的框架RxJava和Retrofit來代替之前的Okhttp的繁瑣請求。

我這邊寫的比較簡單,自己在小專案中更使用的,如果需要深入研究,進行一些封裝的,管理RxJava生命週期的,請移步http://p.codekk.com/detail/Android/RuffianZhong/Rx-Mvp。

retrofit是用來做網路請求操作,RxJava是用來切換執行緒、轉換資料操作的。

首先第一步,使用三方的框架,肯定是先新增依賴包。專案中用的Rxjava2.0、retrofit2.0,而且Rxjava2.0和Rxjava1.0並不相容,所以使用起來需要注意。新增一下依賴。

compile "com.squareup.retrofit2:retrofit:$rootProject.versions.libRetrofit"
compile "com.squareup.retrofit2:converter-gson:$rootProject.versions.libRetrofit"
compile "com.squareup.retrofit2:adapter-rxjava2:$rootProject.versions.libRetrofit"
compile "com.squareup.okhttp3:okhttp:$rootProject.versions.libOkhttp"
compile "com.squareup.okhttp3:logging-interceptor:$rootProject.versions.libOkhttp"
compile "io.reactivex.rxjava2:rxjava:$rootProject.versions.libRxJava"
compile "io.reactivex.rxjava2:rxandroid:$rootProject.versions.libRxAndroid"

第二步,建立一個Api例項  用來獲取介面的請求物件    在init()方法中通過baseUrl或得到Retrofit物件,  請求方法等都是放在介面中,介面與retrofit關聯在getNetDemo()方法中實現。

public class NetDemoApi {
private static NetDemoApi nInstance = new NetDemoApi();
private Retrofit mRequestDemo;
//baseUrl是每一個網路請求的前段,但必須是以 “/”結尾
private String mRequestDemoBaseUrl = "www.baidu.com/";
public static NetDemoApi getInstance(){
return nInstance;
}
private NetDemoApi(){
init();
}

private void init() {
//這一步就把baseurlRetrofit關聯了起來,生成Retrofit物件
mRequestDemo = configure(mRequestDemoBaseUrl);
}

private NetDemo getNetDemo(){
return mRequestDemo.create(NetDemo.class);
}

//配置retrofit
private Retrofit configure(String baseUrl){
HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
WLog.i(message);
}
});
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
//這隻網路請求的攔截器 如果需要獲取到響應頭等相應資訊,在此處就可以獲得 如果不需要可以不寫
builder.networkInterceptors().add(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
Headers headers = response.headers();
List<String> cookies = headers.values("Set-Cookie");
Session session = Session.getInstance();
session.setCookies(Utils.getCookie(cookies));
Log.d(getClass().getSimpleName(),"設定cookie " + session.getCookies());
return response;
}
});
builder.addInterceptor(logging);
builder.connectTimeout(30, TimeUnit.SECONDS);
builder.readTimeout(40, TimeUnit.SECONDS);
OkHttpClient client = builder.build();
return new Retrofit.Builder()
.baseUrl(baseUrl)
.client(client)
//這是rxjava的轉換器,這個是rxjava2的預設介面卡工廠,如果我們需要轉換成bean,可以新增gson的轉換器,直接新增就可以,需要新增依賴包
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
}

第三步,寫實現的介面,這個介面中,才是我們需要請求的路徑  如下   @get 就是一個get請求的方法,     @post就是一個post請求

@url  是直接傳入一個已知的URl進去,直接請求Url,而且跟baseUrl無關,不會跟baseUrl進行拼接;

@Query 就是在URl後面進行鍵值對的拼接,如下  tip傳入1 ,就會把 tip=1 拼接到loginicon=true的後面,get和post請求都是這樣拼接。

@Path 就是把傳入的字串直接傳入註解中{uuid}中的位置處;

@body 是post請求時,傳入的requestBody物件;

@Header  可以給網路請求新增請求頭資訊,新增Cookie就寫cookie,@Header("Cookie") String cookie,

以上傳入的url引數都會和baseUrl進行拼接,得到一個完整的Url去進行網路請求(除了@url)。

返回的就是Observable物件,我們呼叫此方法後,獲得observable物件,接下來用Rxjava進行資料解析,篩選。

public interface NetDemo {
@GET
Observable<ResponseBody> requestDemo(@url String url);
   
  @GET("cgi-bin/mmwebwx-bin/login?loginicon=true")
  Observable<ResponseBody> requestScanResult(@Query("tip") int tip,
  @Query("uuid") String uuid,
  @Query("r") String r,
  @Query("_") String p);

  @POST("qrcode/{uuid}")
  Observable<ResponseBody> requestGenQRCode(@Path("uuid") String uuid,
  @Body RequestBody body);
  @POST("cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN")
  public Observable<ResponseBody> webwxstatusnotify(@Query("pass_ticket") String passTicket,
   @Header("Cookie") String cookie,
   @Body RequestBody body);

}

第四步,在程式碼中進行網路請求,

Observable<ResponseBody> observable = WeChatNetApi.getInstance().getLoginInfo().requestLoginInfo(url);      //返回Observable物件
observable.subscribeOn(Schedulers.io())                                           //進行網路請求是在那個執行緒 io 就是在子執行緒
     .map(new Function<ResponseBody, Bitmap>() {                                 //可以通過map進行轉換,把結果轉換為一個我們需要使用的型別(如demo,返回一個bitmap型別)
    @Override
     public Bitmap apply(@io.reactivex.annotations.NonNull
   ResponseBody responseBody) {
   return BitmapFactory.decodeStream(responseBody.byteStream());
      }
    })
    .flatMap(new Function<String, ObservableSource<Bitmap>>() {                         //還可以通過flatMap轉化為Observable物件,轉換為Observable物件後,還可以繼續進行轉換操作,直到我們需要的型別
     @Override
     public ObservableSource<Bitmap> apply(
     @io.reactivex.annotations.NonNull String uuid) {
     return genQRCode(uuid);
     }
    }
    .filter(new Func1<Community, Boolean>() {                                     //只有返回true,才會繼續向下走,如果返回是false,就不會繼續向下走
      @Override
      public Boolean call(Community community) {
        return community.houses.size()>10;
       }
     })
        .observeOn(AndroidSchedulers.mainThread())                                    //網路請求結束,切換回主執行緒,進行資料處理,或者顯示的操作
    .subscribe(new Observer<ResponseBody>() {                                  //轉換結束,得到了我們需要的資料,進行顯示,先切換到主執行緒
    @Override
     public void onSubscribe(Disposable d) {
      
     }
    @Override
    public void onNext(ResponseBody body) {                                 //訂閱後subscribe會執行的方法
     messageActivity.returnTextInfo(asJsonObject, l);
     }
    @Override
    public void onError(Throwable e) {                                    //如果流程中有報錯,會走到此

    }
    @Override
    public void onComplete() {                                         //onNext之後,如果還有後續的動作,可以在此繼續,onnext後會呼叫complete;

    }
    });



.doOnNext(new Consumer<ResponseBody>() {                                   //doOnNext 直接訂閱是一個偷懶的寫法,這樣寫程式碼比較簡潔,而且這一步操作完之後,我也不需要繼續任何操作
@Override
public void accept(@io.reactivex.annotations.NonNull ResponseBody body) throws Exception {
handleLoginInfoResponse(url,body);
}
}).subscribe();