Retrofit + RxJava + OkHttp 讓網(wǎng)絡(luò)請(qǐng)求變的簡(jiǎn)單-基礎(chǔ)篇

最近因?yàn)槭诸^上的工作做完了,比較閑,想著做一些優(yōu)化。看到以前用的那一套網(wǎng)絡(luò)框架添加一個(gè)請(qǐng)求比較麻煩,并且比較難用,所以想改造一下網(wǎng)絡(luò)框架。現(xiàn)在Android 市面上很火的當(dāng)然是 Retrofit+RxJava + OkHttp, 功能強(qiáng)大,簡(jiǎn)單易用,因此選用這套方案來(lái)改造網(wǎng)絡(luò)庫(kù)。本篇文章是對(duì)Retrofit 的基本使用方法做一些簡(jiǎn)單的介紹。后面會(huì)再寫一篇 Retrofit + RxJava + OkHttp 的封裝過(guò)程。以下是正文。

簡(jiǎn)介:

Retrofit: Retrofit是Square 公司開(kāi)發(fā)的一款正對(duì)Android 網(wǎng)絡(luò)請(qǐng)求的框架。底層基于OkHttp 實(shí)現(xiàn),OkHttp 已經(jīng)得到了google 官方的認(rèn)可。Retrofit官網(wǎng)

OkHttp: 也是Square 開(kāi)源的網(wǎng)絡(luò)請(qǐng)求庫(kù)

RxJava:RxJava 在 GitHub 主頁(yè)上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個(gè)在 Java VM 上使用可觀測(cè)的序列來(lái)組成異步的、基于事件的程序的庫(kù))。這就是 RxJava ,概括得非常精準(zhǔn)。總之就是讓異步操作變得非常簡(jiǎn)單。

各自的職責(zé):Retrofit 負(fù)責(zé)請(qǐng)求的數(shù)據(jù)和請(qǐng)求的結(jié)果,使用接口的方式呈現(xiàn),OkHttp 負(fù)責(zé)請(qǐng)求的過(guò)程,RxJava 負(fù)責(zé)異步,各種線程之間的切換。

RxJava + Retrofit + okHttp 已成為當(dāng)前Android 網(wǎng)絡(luò)請(qǐng)求最流行的方式。

一,Retrofit 寫一個(gè)網(wǎng)絡(luò)請(qǐ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 庫(kù) 
//下面兩個(gè)是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)換器,請(qǐng)求結(jié)果轉(zhuǎn)換成Model 
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'//配合Rxjava 使用

2,創(chuàng)建一個(gè)Retrofit 實(shí)例,并且完成相關(guān)的配置

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

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

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

public interface MovieService { 

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

}

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

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

//獲取接口實(shí)例
MovieService MovieService movieService = retrofit.create(MovieService.class); 
//調(diào)用方法得到一個(gè)Call 
Call<MovieSubject> call = movieService.getTop250(0,20);
 //進(jìn)行網(wǎng)絡(luò)請(qǐ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(); 
      } 
});

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

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

以上就是用Retrofit 完成了一個(gè)網(wǎng)絡(luò)請(qǐng)求,獲取豆瓣top250 榜單電影,效果圖如下:

84193B9F-BBAE-4967-ADB4-F923A422AD64.png

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

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

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

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

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

二,配合RxJava 使用

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

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

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

addCallAdapterFactory(RxJavaCallAdapterFactory.create())

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

addConverterFactory(GsonConverterFactory.create())

4,Activity 或者 Fragment 中傳入 Subscriber 建立訂閱關(guān)系

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)絡(luò)請(qǐng)求,返回不再是一個(gè)Call ,而是一個(gè)Observable, 在Activity / Fragment 中傳入一個(gè)Subscriber 建立訂閱關(guān)系,就可以在 onNext 中處理結(jié)果了,RxJava 的好處是幫我處理線程之間的切換,我們可以在指定訂閱的在哪個(gè)線程,觀察在哪個(gè)線程。我們可以通過(guò)操作符進(jìn)行數(shù)據(jù)變換。整個(gè)過(guò)程都是鏈?zhǔn)降模?jiǎn)化邏輯。其中FlatMap 操作符 還可以解除多層嵌套的問(wèn)題。總之,RxJava 很強(qiáng)大,能幫我處理很多復(fù)雜的場(chǎng)景,如果熟練使用的話,那么能提升我們的開(kāi)發(fā)效率。這里不打算講RxJava 的內(nèi)容,如果還不了解RxJava ,或者還對(duì)RxJava不熟悉的話,推薦幾篇寫很優(yōu)秀的博客。

1,RxJava 的經(jīng)典文章,扔物線的 給 Android 開(kāi)發(fā)者的 RxJava 詳解
2,關(guān)于RxJava 友好的文章
3,關(guān)于RxJava 友好的文章-進(jìn)階

三,加入 OkHttp 配置

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

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

  // 添加公共參數(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();

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

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

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

參考博客:
1,Retrofit用法詳解
2,基于Retrofit、OkHttp、Gson封裝通用網(wǎng)絡(luò)框架
3, RxJava 與 Retrofit 結(jié)合的最佳實(shí)踐

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,382評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 176,038評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 62,853評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,616評(píng)論 6 408
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 55,112評(píng)論 1 323
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 42,355評(píng)論 0 288
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,869評(píng)論 1 334
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,727評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,928評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,165評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 34,570評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 35,813評(píng)論 1 282
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,585評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,892評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容