Android用Retrofit搭建通用網(wǎng)絡(luò)請求模塊

Retrofit是現(xiàn)在十分流行的網(wǎng)絡(luò)請求庫,底層封裝了OkHttp肛根,實現(xiàn)了JSON和POJO的互相轉(zhuǎn)換像鸡,網(wǎng)絡(luò)請求回來直接是對象活鹰,簡化業(yè)務(wù)邏輯,用起來十分爽坟桅。

本文將會簡單介紹下Retrofit的使用方法华望,主要描述下自己寫的一個通用網(wǎng)絡(luò)請求模塊。

配置Retrofit

在build.gradle中添加依賴引入Retrofit仅乓,目前最新版本是2.1.0:

compile 'com.squareup.retrofit2:retrofit:2.1.0'

對Json的序列化和反序列化赖舟,Retrofit提供了gson、jackson等多種轉(zhuǎn)換器夸楣。我用的是gson宾抓,需要額外添加依賴:

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

創(chuàng)建Retrofit對象用的是Builder模式,同時可以設(shè)置底層的OkHttpClinet參數(shù)豫喧。

OkHttpClient okHttpClient = new OkHttpClient.Builder()
        .addInterceptor(new LoggingInterceptor())
        .addNetworkInterceptor(new StethoInterceptor())
        .connectTimeout(HTTP_CONNECT_TIMEOUT, TimeUnit.SECONDS)
        .readTimeout(HTTP_READ_TIMEOUT, TimeUnit.SECONDS)
        .writeTimeout(HTTP_WRITE_TIMEOUT, TimeUnit.SECONDS)
        .build();
Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(mHost)
        .addConverterFactory(GsonConverterFactory.create())
        .client(okHttpClient)
        .build();
  • LoggingInterceptor請求攔截器石洗,后面會介紹;
  • Stetho是Facebook出品的Android可視化工具紧显,利用Chrome Developer Tools提供sqlit讲衫、preference、network等操作孵班,推薦去了解涉兽;
  • GsonConverterFactory是上面講的Json轉(zhuǎn)換器,如果要對Json做特別的處理篙程,可以在create()傳入自定義Gson枷畏;

請求api

請求api定義在interface,下面是用于登錄的Post請求例子虱饿,返回值是類似于OkHttp的call拥诡。

@FormUrlEncoded
@POST("/api/login/")
Call<LoginResponse> doLoginIn(@FieldMap() TreeMap<String, String> paramMap);

入?yún)⑿问娇梢杂卸喾N触趴,提供對請求的不同處理,詳細可以查官網(wǎng)渴肉。

  • @Query冗懦、@QueryMap:get請求的query參數(shù)
  • @File、@FieldMap:form-url-encoded參數(shù)
  • @Part:文件
  • @Url:可傳入完整url

發(fā)出一個請求

獲得Retrofit對象和定義好請求的api之后宾娜,就可以發(fā)出網(wǎng)絡(luò)請求批狐,下面是同步和異步的例子。

ApiDefine service = retrofit.create(ApiDefine.class);
//同步
Call<LoginResponse> call = service.doLoginIn(paramMap);
retrofit2.Response<LoginResponse> response = call.execute();
LoginResponse loginResponse = response.body().
//異步
call.enqueue(new Callback<LoginResponse>() {
            @Override
            public void onResponse(Call<LoginResponse> call, retrofit2.Response<LoginResponse> response) {   
            }

            @Override
            public void onFailure(Call<LoginResponse> call, Throwable t) {
            }
        });

paramMap是一個Map前塔,請求用到的參數(shù)都放在里面。使用execute()發(fā)出同步請求承冰,或者enqueue()發(fā)出異步請求华弓。響應(yīng)結(jié)果用response.body()獲取定義好的LoginResponse,Retrofit會自動將json字符串轉(zhuǎn)換進LoginResponse困乒。

通用的請求響應(yīng)結(jié)果

一般服務(wù)器會返回通用的請求結(jié)果和對應(yīng)的業(yè)務(wù)數(shù)據(jù)寂屏,可以考慮使用一個通用請求基類HttpResponse,里面定義固定的返回結(jié)果娜搂。

private int result;
private String message;
private long timestamp;
private T data;

重點是data這個泛型迁霎,支持不同接口返回不同的具體業(yè)務(wù)數(shù)據(jù),只要設(shè)置不同的響應(yīng)類就行百宇。相應(yīng)地考廉,登錄api修改如下:

@FormUrlEncoded
@POST("/api/login/")
Call<HttpResponse<LoginResponse>> doLoginIn(@FieldMap() TreeMap<String, String> paramMap);

發(fā)送方法修改為支持泛型:

  private <T extends BaseBizResponse> HttpResponse<T> doSend(Call<HttpResponse<T>> call) throws Exception {
        retrofit2.Response<HttpResponse<T>> response;
        try {
            response = call.execute();
        } catch (Exception e) {
            //throw Exception
        }

        if (response.isSuccessful()) {
            return response.body();
        } else {
            //throw Exception
      }
}  

泛型T增加實現(xiàn)BaseBizResponse這個業(yè)務(wù)用的基類,里面可以定義一些公共變量或者方法携御。

RxJava提供異步處理

自己開線程處理網(wǎng)絡(luò)請求是可以昌粤,但不如用專門的異步處理工具。RxJava是一個提供異步的啄刹、響應(yīng)式編程的庫涮坐,入門有點難度,但和Retrofit配合十分合適誓军。

 public <T extends BaseBizResponse> Observable<T> send(final Call<HttpResponse<T>> call, Scheduler subscribeScheduler, Scheduler observeScheduler) {
        return Observable.create(new Observable.OnSubscribe<HttpResponse<T>>() {
            @Override
            public void call(Subscriber<? super HttpResponse<T>> subscriber) {
                HttpResponse<T> httpResponse = doSend(call);
                subscriber.onNext(httpResponse);
            }
        }).map(new Func1<HttpResponse<T>, T>() {
            @Override
            public T call(HttpResponse<T> httpResponse) {
                return dealHttpResponse(call, httpResponse);
            }
        }).subscribeOn(subscribeScheduler)
                .observeOn(observeScheduler);

    }

subscribeOn()指定網(wǎng)絡(luò)請求運行在什么線程袱讹,可以新建一個線程或者使用線程池;observeOn()指定網(wǎng)絡(luò)請求完成后在什么線程觀察執(zhí)行結(jié)果昵时,可以指定回到Android主線程捷雕。

send方法返回Observable,這是一個可以被觀察的對象债查。觀察結(jié)果時非区,調(diào)用subscribe可以指定三種Action,分別對應(yīng)onNext盹廷,onError征绸,onComplete,這里使用了onNext和onError,處理成功和失敗兩種情況管怠。繼承Action1實現(xiàn)SuccessAction和FailAction淆衷,就算不懂RxJava,也可以照葫蘆畫瓢調(diào)用網(wǎng)絡(luò)請求渤弛。

 observable.subscribe(new SuccessAction<LoginResponse>() {

            @Override
            public void call(LoginResponse loginResponse) {
              
            }
        }, new FailAction<Throwable>() {
            @Override
            public void call(Throwable throwable) {
               
            }
        });

對于服務(wù)器返回的結(jié)果祝拯,往往更專注于業(yè)務(wù)數(shù)據(jù),所以加了一個步驟她肯,將HttpResponse<T>轉(zhuǎn)換為T佳头,只留下業(yè)務(wù)響應(yīng)類。并且晴氨,將服務(wù)器報錯的請求直接拋出異常康嘉,由FailAction處理。

調(diào)用dealHttpResponse()用到了map()方法籽前,這是RxJava一個操作符亭珍,用于對對象的轉(zhuǎn)換。

    private <T extends BaseBizResponse> T dealHttpResponse(Call<HttpResponse<T>> call, HttpResponse<T> httpResponse) {
        if (httpResponse.getResult() != RESPOND_RESULT_OK) {
            //throw exception;
        }
        return (T) httpResponse.getData();
    }

本文沒有詳細介紹RxJava枝哄,但非常推薦你去深入學(xué)習(xí)肄梨。一旦你弄懂RxJava,你會發(fā)現(xiàn)它真的太好用了挠锥。RxJava代碼如果改用lambda众羡,會更加簡潔精妙。

請求攔截

Retrofit的請求攔截使用OkHttp里面的Interceptor瘪贱,得到Request和Response后就可以做各種自定義操作纱控。比如想獲取每個請求的響應(yīng)時間,可以這樣實現(xiàn):

public static class LoggingInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            long t1 = System.nanoTime();
            Response response = chain.proceed(request);
            long t2 = System.nanoTime();
            LogUtils.d(String.format("HTTP響應(yīng)請求 %s %s %.1fms", response.request().url(), response.request().method(), time));
            return response;
        }
    }

文件下載

請求文件的下載菜秦,基本方法差不多甜害,api定義改成傳入url,返回ResponseBody對象球昨。

@GET
@Streaming
Call<ResponseBody> download(@Url String url);

最終可以從ResponseBody對象獲得InputStream尔店,然后按照合適的方法寫入磁盤,這里不貼代碼了主慰。

retrofit2.Response<ResponseBody> retrofitResponse = call.execute();
InputStream inputStream = retrofitResponse.body().byteStream();

總結(jié)

Retrofit+RxJava十分好用嚣州,學(xué)Android的一定要學(xué)習(xí)下。我一直在改進這個網(wǎng)絡(luò)請求模塊共螺,有好的建議就告訴我啦该肴。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市藐不,隨后出現(xiàn)的幾起案子匀哄,更是在濱河造成了極大的恐慌秦效,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件涎嚼,死亡現(xiàn)場離奇詭異阱州,居然都是意外死亡,警方通過查閱死者的電腦和手機法梯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門苔货,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人立哑,你說我怎么就攤上這事夜惭。” “怎么了刁憋?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵滥嘴,是天一觀的道長。 經(jīng)常有香客問我至耻,道長,這世上最難降的妖魔是什么镊叁? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任尘颓,我火速辦了婚禮,結(jié)果婚禮上晦譬,老公的妹妹穿的比我還像新娘疤苹。我一直安慰自己,他們只是感情好敛腌,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布卧土。 她就那樣靜靜地躺著,像睡著了一般像樊。 火紅的嫁衣襯著肌膚如雪尤莺。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天生棍,我揣著相機與錄音颤霎,去河邊找鬼。 笑死涂滴,一個胖子當(dāng)著我的面吹牛友酱,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播柔纵,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼缔杉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了搁料?” 一聲冷哼從身側(cè)響起或详,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤系羞,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后鸭叙,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體觉啊,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年沈贝,在試婚紗的時候發(fā)現(xiàn)自己被綠了杠人。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡宋下,死狀恐怖嗡善,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情学歧,我是刑警寧澤罩引,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站枝笨,受9級特大地震影響袁铐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜横浑,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一剔桨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧徙融,春花似錦洒缀、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至隐轩,卻和暖如春饺饭,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背龙助。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工砰奕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人提鸟。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓军援,卻偏偏與公主長得像,于是被迫代替她去往敵國和親称勋。 傳聞我的和親對象是個殘疾皇子胸哥,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355

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