Retrofit 基礎解析

    首先呢,剛開始接觸retrofit,有很多都是從其他博客那整理過來的,如果有不正確的地方,歡迎各位大佬指正。


Retrofit是什麼?

    Retrofit簡單的說就是一個網絡請求的適配器,它將一個基本的Java接口通過動態代理的方式翻譯成一個HTTP請求,並通過OkHttp去發送請求。Retrofit底層是使用OKHttp封裝的。準確來說,網絡請求的工作本質上是OkHttp完成,而 Retrofit 僅負責網絡請求接口的封裝。它的一個特點是包含了特別多註解,方便簡化你的代碼量,此外它還具有強大的可擴展性,支持各種格式轉換以及RxJava。


Retrofit的好處?

  • 解耦        

        我們在請求接口數據的時候,API接口定義和API接口使用總是相互影響,什麼傳參、回調等,耦合在一塊。有時候我們會考慮一下怎麼封裝我們的代碼讓這兩個東西不那麼耦合,這個就是Retrofit的解耦目標,也是它的最大的特點。

  • 可以配置不同HttpClient來實現網絡請求,如OkHttp、HttpClient...
  • 支持同步、異步和RxJava
  • 可以配置不同的反序列化工具來解析數據,如json、xml...
  • 請求速度快,使用非常方便靈活

Retrofit註解

     請求註解:

註解代碼請求格式
@GETGET請求
@POSTPOST請求
@DELETEDELETE請求
@HEADHEAD請求
@OPTIONSOPTIONS請求
@PATCHPATCH請求

    請求參數:

註解代碼說明
@Headers添加請求頭
@Path替換路徑
@Query替代參數值,通常是結合get請求的
@FormUrlEncoded用表單數據提交
@Field替換參數值,是結合post請求的


下面我們詳細說說這些註解:

 一、首先添加依賴,添加網絡權限,創建接收服務器返回數據的類:

public class News {
    // 根據返回數據的格式和數據解析方式(Json、XML等)定義
    ...
}

二、創建用於描述網絡請求的接口

public interface APi{
    // @GET註解的作用:採用Get方法發送網絡請求
    // getNews(...) = 接收網絡請求數據的方法
    // 其中返回類型爲Call<News>,News是接收數據的類(即上面定義的News類)
    // 如果想直接獲得Responsebody中的內容,可以定義網絡請求返回值爲Call<ResponseBody>
    @Headers("apikey:81bf9da930c7f9825a3c3383f1d8d766")
    @GET("word/word")
    Call<News> getNews(@Query("num") String num,@Query("page")String page);
}

①Retrofit將Http請求抽象成Java接口,並在接口裏面採用註解來配置網絡請求參數。用動態代理將該接口的註解“翻譯”成一個Http請求,最後再執行 Http請求
        注意: 接口中的每個方法的參數都需要使用註解標註,否則會報錯

②APi接口中的最後一個註釋,Responsebody是Retrofit網絡請求回來的原始數據類,沒經過Gson轉換什麼的,如果你不想轉換,比如我就想看看接口返回的json字符串,那就像註釋中說的,把Call的泛型定義爲ResponseBody:Call<ResponseBody>

③GET註解:說白了就是我們的GET請求方式。

        這裏涉及到Retrofit創建的一些東西,Retrofit在創建的時候,有一行代碼:

baseUrl("http://apis.baidu.com/txapi/")

     這個http://apis.baidu.com/txapi/是我們要訪問的接口的BaseUrl,而我們現在用GET註解的字符串 "word/word"會追加到BaseUrl中變爲:http://apis.baidu.com/txapi/world/world

④@Query

@Query("num")String num, @Query("page")String page;
     就是鍵值對,Retrofit會把這兩個字段一塊拼接到接口中,追加到http://apis.baidu.com/txapi/world/world後面,變爲http://apis.baidu.com/txapi/world/world?num=10&page=1,這樣,這個帶着響應頭的接口就是我們最終請求網絡的完整接口。

        補充一點哈,GET請求方式,如果攜帶的參數不是以"?num=10&page=1"拼接到接口中(就是不帶?分隔符),那就不用Query註解了,而是使用Path註解:

public interface NewsServicr{
   @Get("News/{newsId}")
   Call<News> getNews(@Path("newsId") String newsId);
}
        上面的GET註解的接口通過{ }佔位符來標記的newId,就用@Path註解在傳入newsId的值。
        @Query與@Path功能相同,但區別明顯不一樣。像@Query的例子,我如果使用@Path來註解,那麼程序就會報錯。這塊要搞清楚!
        還有一點,有的url既有“{}”佔位符,又有“?”後面的鍵值對(key-value),那Retrofit既得使用@Query註解又得使用@Path註解,也就是說,兩者可以同時使用。

⑤@Headers

@Headers("apikey:81bf9da930c7f9825a3c3383f1d8d766")
        這個很好理解,這個接口需要添加的header:apikey:81bf9da930c7f9825a3c3383f1d8d766
        @Headers就是把接口的header註解進去。
        還有很多添加header的方式,比如:
public interface APi {
    @GET("word/word")
    Call<News> getNews(@Header("apikey")String apikey, @Query("num")String num, @Query("page")String page);
}

        這個就是在代碼中動態的添加header,用法如下:

Call<News> news = mApi.getNews("81bf9da930c7f9825a3c3383f1d8d766", "1",  "10");

        這裏再補充一點:@Header與@Headers的區別

        舉個例子:

//@Header
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)

//@Headers
@Headers("Authorization:authorization")
@GET("user")
Call<User> getUser()

        以上兩個方法的效果是一致的。
        區別就在於使用場景和使用方式
        使用場景:@Header用於添加不固定的請求頭,@Headers用於添加固定的請求頭

        使用範圍:@Header作用於方法的參數;@Headers作用於方法

三、創建Retrofit對象:

Retrofit retrofit = new Retrofit.Builder()
        //設置數據解析器
        .addConverterFactory(GsonConverterFactory.create())
        //設置網絡請求的Url地址
        .baseUrl("http://apis.baidu.com/txapi/")
        .build();
// 創建網絡請求接口的實例
APi mApi = retrofit.create(APi.class);

 

處特意說明一下這個網絡請求的URL的組成:Retrofit把網絡請求的URL 分成了兩部分設置:

        第一部分:在創建Retrofit實例時通過.baseUrl()設置:  "baseUrl("http://apis.baidu.com/txapi/")"

        第二部分:在網絡請求接口的註解設置,就是在上面的APi接口中用GET註解的字符串:@Get("word/word")

        Retrofit的網絡請求的完整Url = 創建Retrofit實例時通過.baseUrl()設置的url + 網絡請求接口的註解設置


②關於數據解析器(Converter)

//設置數據解析器
.addConverterFactory(GsonConverterFactory.create())
        這個有啥用?這句話的作用就是使得來自接口的json結果會自動解析成定義好了的字段和類型都相符的json對象接受類。在Retrofit 2.0中,Package 中已經沒有Converter了,所以,你需要自己創建一個Converter, 不然的話Retrofit只能接收字符串結果,你也只能拿到一串字符,剩下的json轉換的活還得你自己來幹。所以,如果你想接收json結果並自動轉換成解析好的接收類,必須自己創建Converter對象,然後使用addConverterFactory把它添加進來!
        Retrofit支持多種數據解析方式,在使用時注意需要在Gradle添加依賴:

數據解析器Gradle依賴
Gsoncom.squareup.retrofit2:converter-gson:2.0.2
Jacksoncom.squareup.retrofit2:converter-jackson:2.0.2
Simple XMLcom.squareup.retrofit2:converter-simplexml:2.0.2
Protobufcom.squareup.retrofit2:converter-protobuf:2.0.2
Moshicom.squareup.retrofit2:converter-moshi:2.0.2
Wirecom.squareup.retrofit2:converter-wire:2.0.2
Scalarscom.squareup.retrofit2:converter-scalars:2.0.2
        我們的實例中就是使用了第一種Gson數據解析器。

③再來引入另一個方法:addCallAdapterFactory()
        上文代碼中沒有這個方法,但是得知道它的作用,有必要作爲補充知識點

        看一下我們的接口返回:

Call<News> news = mApi.getNews("1", "10");

        返回的Call<News>可以理解成源生的了,默認就這麼寫。但像很多很多項目都是結合着RXJava來使用這個Retrofit的,那麼這個接口返回就會被定義爲(僞代碼):

Observable<News> news = mApi.getNews("1", "10").subscribeOn(...).observeOn(...);
        它返回的是一個Observable類型(觀察者模式)。從上面可以看到,Retrofit接口的返回值可以分爲兩部分,第一部分是返回值類型:Call或者Observable,另一部分是泛型:News
addCallAdapterFactory()影響的就是第一部分:Call或者Observable。Call類型是Retrofit默認支持的(Retrofit內部有一個DefaultCallAdapterFactory),所以你如果不用RXJava + Retrofit結合使用,那就自動忽略掉這個方法,而如果你想要支持RXJava(就是想把返回值定義爲Observable對象),就需要我們自己用addCallAdapterFactory()添加:addCallAdapterFactory(RxJavaCallAdapterFactory.create())

        像我們項目中Retrofit創建的代碼就是:

retrofit = new Retrofit.Builder()
                        .baseUrl(URL.SERVICE_URL)
                        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                        .addConverterFactory(GsonConverterFactory.create())
                        .client(okHttpClient)
                        .build();

        同理,Retrofit不光支持多種數據解析器,也支持多種網絡請求適配器:Guava、Java8、RXJava ,使用時也需要在Gradle添加依賴:

網絡請求適配器Gradle依賴
Guavacom.squareup.retrofit2:adapter-guava:2.0.2
Java8com.squareup.retrofit2:adapter-java8:2.0.2
RXJavacom.squareup.retrofit2:adapter-rxjava:2.0.2
        示例代碼就是用的RXJava。

四、發起網絡請求

//對發送請求進行封裝
Call<News> news = mApi.getNews("1", "10");
//發送網絡請求(異步)
news.enqueue(new Callback<News>() {
    //請求成功時回調
    @Override
    public void onResponse(Call<News> call, Response<News> response) {
       //請求處理,輸出結果-response.body().show();
    }

    @Override
    public void onFailure(Call<News> call, Throwable t) {
       //請求失敗時候的回調
    }
});
        上面是一個簡單的GET請求的全過程。

        補充一點,Retrofit還有個發起同步網絡請求的方法:

//對發送請求進行封裝
Call<News> news = mApi.getNews("1", "10");
//發送網絡請求(同步)
Response<Reception> response = news.execute();
        而對於POST的瞭解還比較少,等以後積累了這部分知識再補上。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章