18.RxJava與Retrofit

一、RxJava
1,基本用法
創(chuàng)建 Observable、創(chuàng)建 Observer、 Subscribe
Observable一般用create(),也有just()、from()。
比如依次打印字符串數(shù)組 names 中的所有字符串:

String[] names = ...;
Observable.from(names)
    .subscribe(new Action1<String>() {
        @Override
        public void call(String name) {
            Log.d(tag, name);
        }
    });

2.線程控制Scheduler
在不指定線程的情況下, RxJava 遵循的是線程不變的原則,即:在哪個線程調(diào)用 subscribe(),就在哪個線程生產(chǎn)事件;在哪個線程生產(chǎn)事件,就在哪個線程消費事件。如果需要切換線程,就需要用到 Scheduler。
Scheduler方法有immediate()、newThread()、io()、computation()??梢允褂?subscribeOn()(發(fā)生線程) 和 observeOn() (運行線程)兩個方法來對線程進行控制了。
比如:

Observable.just(1, 2, 3, 4)
    .subscribeOn(Schedulers.io()) // 指定 subscribe() 發(fā)生在 IO 線程
    .observeOn(AndroidSchedulers.mainThread()) // 指定 Subscriber 的回調(diào)發(fā)生在主線程
    .subscribe(new Action1<Integer>() {
        @Override
        public void call(Integer number) {
            Log.d(tag, "number:" + number);
        }
    });

3.變換
將事件序列中的對象或整個序列進行加工處理,轉(zhuǎn)換成不同的事件或事件序列。
主要有map() 、flatMap()

二、Retrofit
1.定義API接口:

public interface PhoneService {
    @GET("/apistore/mobilenumber/mobilenumber")
    Call<PhoneResult> getResult(@Header("apikey") String apikey, @Query("phone") String phone);
}
private static final String BASE_URL = "http://apis.baidu.com";
private static final String API_KEY = "8e13586b86e4b7f3758ba3bd6c9c9135";
 
private void query(){
    //1.創(chuàng)建Retrofit對象
    Retrofit retrofit = new Retrofit.Builder()
            .addConverterFactory(GsonConverterFactory.create())//解析方法
            .baseUrl(BASE_URL)//主機地址
            .build();
            
    //2.創(chuàng)建訪問API的請求
    PhoneService service = retrofit.create(PhoneService.class);
    Call<PhoneResult> call = service.getResult(API_KEY, phoneView.getText().toString());
    
    //3.發(fā)送請求
    call.enqueue(new Callback<PhoneResult>() {
        @Override
        public void onResponse(Call<PhoneResult> call, Response<PhoneResult> response) {
            //4.處理結(jié)果
            if (response.isSuccess()){
                PhoneResult result = response.body();
                if (result != null){
                    PhoneResult.RetDataEntity entity = result.getRetData();
                }
            }
        }
 
        @Override
        public void onFailure(Call<PhoneResult> call, Throwable t) {
 
        }
    });
}

3.結(jié)合RxJava

public interface Api {
    @GET
    Observable<LoginResponse> login(@Body LoginRequest request);

    @GET
    Observable<RegisterResponse> register(@Body RegisterRequest request);
}
private static Retrofit create() {
            OkHttpClient.Builder builder = new OkHttpClient().newBuilder();
            builder.readTimeout(10, TimeUnit.SECONDS);
            builder.connectTimeout(9, TimeUnit.SECONDS);

            if (BuildConfig.DEBUG) {
                HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
                interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
                builder.addInterceptor(interceptor);
            }

            return new Retrofit.Builder().baseUrl(ENDPOINT)
                    .client(builder.build())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .build();
}
Api api = retrofit.create(Api.class);
        api.login(request)
              .subscribeOn(Schedulers.io())               //在IO線程進行網(wǎng)絡請求
             .observeOn(AndroidSchedulers.mainThread())  //回到主線程去處理請求結(jié)果
            .subscribe(new Observer<LoginResponse>() {
                    @Override
                public void onSubscribe(Disposable d) {}

                @Override
                public void onNext(LoginResponse value) {}

                @Override
                public void onError(Throwable e) {
                    Toast.makeText(mContext, "登錄失敗", Toast.LENGTH_SHORT).show();
                }

                @Override
                public void onComplete() {
                    Toast.makeText(mContext, "登錄成功", Toast.LENGTH_SHORT).show();
                }
            });

三、RxBinding
比如點擊監(jiān)聽:

Button button = ...;
RxView.clickEvents(button) // 以 Observable 形式來反饋點擊事件
    .subscribe(new Action1<ViewClickEvent>() {
        @Override
        public void call(ViewClickEvent event) {
            // Click handling
        }
    });

RxView.clickEvents(button)
    .throttleFirst(500, TimeUnit.MILLISECONDS)
    .subscribe(clickAction);
示例:RxJava + Retrofit + okHttp
一,Retrofit 寫一個網(wǎng)絡請求

以獲取豆瓣 Top250 榜單為例,地址:https://api.douban.com/v2/movie/

1,首先,要使用Retrofit ,你肯定需要把它的包引入,在你的build.gradle文件中添加如下配置:

 compile 'com.squareup.retrofit2:retrofit:2.1.0'//retrofit 
 compile 'com.google.code.gson:gson:2.6.2'//Gson 庫 
//下面兩個是RxJava 和RxAndroid 
compile 'io.reactivex:rxjava:1.1.0' 
compile 'io.reactivex:rxandroid:1.1.0'  
compile 'com.squareup.retrofit2:converter-gson:2.1.0'//轉(zhuǎn)換器,請求結(jié)果轉(zhuǎn)換成Model 
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'//配合Rxjava 使用

2,創(chuàng)建一個Retrofit 實例,并且完成相關的配置

public static final String BASE_URL = "https://api.douban.com/v2/movie/";
Retrofit retrofit = new Retrofit.Builder() 
       .baseUrl(BASE_URL) 
       .addConverterFactory(GsonConverterFactory.create())
       .build();

說明:配置了接口的baseUrl和一個converter,GsonConverterFactory 是默認提供的Gson 轉(zhuǎn)換器,Retrofit 也支持其他的一些轉(zhuǎn)換器,詳情請看官網(wǎng)Retrofit官網(wǎng)

3,創(chuàng)建一個 接口 ,代碼如下:

public interface MovieService { 

 //獲取豆瓣Top250 榜單 
 @GET("top250")
 Call<MovieSubject> getTop250(@Query("start") int start,@Query("count")int count);

}

說明:定義了一個方法getTop250,使用get請求方式,加上@GET 標簽,標簽后面是這個接口的 尾址top250,完整的地址應該是 baseUrl+尾址 ,參數(shù) 使用@Query標簽,如果參數(shù)多的話可以用@QueryMap標簽,接收一個Map

4,用Retrofit 創(chuàng)建 接口實例 MoiveService,并且調(diào)用接口中的方法進行網(wǎng)絡請求,代碼如下:

//獲取接口實例
MovieService MovieService movieService = retrofit.create(MovieService.class); 
//調(diào)用方法得到一個Call 
Call<MovieSubject> call = movieService.getTop250(0,20);
 //進行網(wǎng)絡請求 
call.enqueue(new Callback<MovieSubject>() {
       @Override 
       public void onResponse(Call<MovieSubject> call, Response<MovieSubject> response) { 
            mMovieAdapter.setMovies(response.body().subjects);     
            mMovieAdapter.notifyDataSetChanged(); 
       } 
      @Override 
      public void onFailure(Call<MovieSubject> call, Throwable t) { 
         t.printStackTrace(); 
      } 
});

以上是異步方式請求,還有同步方式execute(),返回一個Response,代碼如下:

Response<MovieSubject> response = call.execute();

以上就是用Retrofit 完成了一個網(wǎng)絡請求,獲取豆瓣top250 榜單電影。

以上示例是用get方式完成,如果要使用post 方式,我們只需要修改一下接口中的方法定義,如下:

public interface MovieService { 
        //獲取豆瓣Top250 榜單 
       @FormUrlEncoded
       @POST("top250") 
       Call<MovieSubject> getTop250(@Field("start") int start, @Field("count") int count);
}

說明:使用POST 請求方式時,只需要更改方法定義的標簽,用@POST 標簽,參數(shù)標簽用 @Field 或者@Body或者FieldMap,注意:使用POST 方式時注意2點,1,必須加上 @FormUrlEncoded標簽,否則會拋異常。2,使用POST方式時,必須要有參數(shù),否則會拋異常, 源碼拋異常的地方如下:

if (isFormEncoded && !gotField) { 
      throw methodError("Form-encoded method must contain at least one @Field."); 
}

以上就是一個使用Retrofit 完成一個網(wǎng)絡請求的完整示例,其他標簽使用方式請看官網(wǎng)Retrofit官網(wǎng),官網(wǎng)用法也介紹的比較詳細,此外,發(fā)現(xiàn)了一篇博客也介紹得比較詳細,Retrofit用法詳解

二,配合RxJava 使用

1, 更改定義的接口,返回值不再是一個Call ,而是返回的一個Observble.

public interface MovieService { 
    //獲取豆瓣Top250 榜單  
    @GET("top250") 
    Observable<MovieSubject> getTop250(@Query("start") int start, @Query("count")int count);
 }

2,創(chuàng)建Retrofit 的時候添加如下代碼

addCallAdapterFactory(RxJavaCallAdapterFactory.create())

3,添加轉(zhuǎn)換器Converter(將json 轉(zhuǎn)為JavaBean)

addConverterFactory(GsonConverterFactory.create())

4,Activity 或者 Fragment 中傳入 Subscriber 建立訂閱關系

Subscription subscription = movieService.getTop250(0,20) 
.subscribeOn(Schedulers.io()) 
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<MovieSubject>() { 
@Override
 public void onCompleted() { 

 } 
@Override 
public void onError(Throwable e) { 

} 
@Override
 public void onNext(MovieSubject movieSubject) { 
        mMovieAdapter.setMovies(movieSubject.subjects); 
        mMovieAdapter.notifyDataSetChanged(); 
   } 
});

以上是加入RxJava 后的網(wǎng)絡請求,返回不再是一個Call ,而是一個Observable, 在Activity / Fragment 中傳入一個Subscriber 建立訂閱關系,就可以在 onNext 中處理結(jié)果了,RxJava 的好處是幫我處理線程之間的切換,我們可以在指定訂閱的在哪個線程,觀察在哪個線程。我們可以通過操作符進行數(shù)據(jù)變換。整個過程都是鏈式的,簡化邏輯。其中FlatMap 操作符 還可以解除多層嵌套的問題??傊琑xJava 很強大,能幫我處理很多復雜的場景,如果熟練使用的話,那么能提升我們的開發(fā)效率。這里不打算講RxJava 的內(nèi)容,如果還不了解RxJava ,或者還對RxJava不熟悉的話,推薦幾篇寫很優(yōu)秀的博客。

1,RxJava 的經(jīng)典文章,扔物線的 給 Android 開發(fā)者的 RxJava 詳解

2,關于RxJava 友好的文章

3,關于RxJava 友好的文章-進階

三,加入 OkHttp 配置

通過OkHttpClient 可以配置很多東西,比如鏈接超時時間,緩存,攔截器等等。代碼如下:

// 創(chuàng)建 OKHttpClient 
OkHttpClient.Builder builder = new OkHttpClient.Builder(); 
     builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//連接超時時間 
     builder.writeTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//寫操作 超時時間 
     builder.readTimeout(DEFAULT_TIME_OUT,TimeUnit.SECONDS);//讀操作超時時間 

  // 添加公共參數(shù)攔截器 
BasicParamsInterceptor basicParamsInterceptor = new BasicParamsInterceptor.Builder() 
    .addHeaderParam("userName","")//添加公共參數(shù) 
    .addHeaderParam("device","") 
    .build(); 

 builder.addInterceptor(basicParamsInterceptor); 

// 創(chuàng)建Retrofit
 mRetrofit = new Retrofit.Builder() 
     .client(builder.build()) 
     .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 
     .addConverterFactory(GsonConverterFactory.create()) 
     .baseUrl(ApiConfig.BASE_URL) 
     .build();

以上只是配置了一些簡單的項,如,連接超時時間,實際項目中,我們可能有一些公共的參數(shù),如 ,設備信息,渠道,Token 之類的,每個接口都需要用,我們可以寫一個攔截器,然后配置到OKHttpClient里,通過 builder.addInterceptor(basicParamsInterceptor) 添加,這樣我們就不用每個接口都添加這些參數(shù)了。緩存也可以通過寫一個攔截器來實現(xiàn)(后面文章再講)。

以上就是Retrofit+RxJava+OkHttp實現(xiàn)網(wǎng)絡請求的簡單演示,如果每個接口都這么寫的話,代碼量太多,而且不優(yōu)雅。所以還需要我們封裝一下,由于篇幅有限,封裝放到下一篇文章。

** Retrofit + RxJava + OkHttp 封裝已更新,請看Retrofit + RxJava + OkHttp 讓網(wǎng)絡請求變的簡單-封裝篇**

參考博客:

1,Retrofit用法詳解

2,基于Retrofit、OkHttp、Gson封裝通用網(wǎng)絡框架

3, RxJava 與 Retrofit 結(jié)合的最佳實踐

作者:依然范特稀西
鏈接:http://www.itdecent.cn/p/5bc866b9cbb9
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。</pre>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容