首先呢,剛開始接觸retrofit,有很多都是從其他博客那整理過來的,如果有不正確的地方,歡迎各位大佬指正。
Retrofit是什麼?
Retrofit簡單的說就是一個網絡請求的適配器,它將一個基本的Java接口通過動態代理的方式翻譯成一個HTTP請求,並通過OkHttp去發送請求。Retrofit底層是使用OKHttp封裝的。準確來說,網絡請求的工作本質上是OkHttp完成,而 Retrofit 僅負責網絡請求接口的封裝。它的一個特點是包含了特別多註解,方便簡化你的代碼量,此外它還具有強大的可擴展性,支持各種格式轉換以及RxJava。
Retrofit的好處?
- 解耦
我們在請求接口數據的時候,API接口定義和API接口使用總是相互影響,什麼傳參、回調等,耦合在一塊。有時候我們會考慮一下怎麼封裝我們的代碼讓這兩個東西不那麼耦合,這個就是Retrofit的解耦目標,也是它的最大的特點。
- 可以配置不同HttpClient來實現網絡請求,如OkHttp、HttpClient...
- 支持同步、異步和RxJava
- 可以配置不同的反序列化工具來解析數據,如json、xml...
- 請求速度快,使用非常方便靈活
Retrofit註解
請求註解:
註解代碼 | 請求格式 |
---|---|
@GET | GET請求 |
@POST | POST請求 |
@DELETE | DELETE請求 |
@HEAD | HEAD請求 |
@OPTIONS | OPTIONS請求 |
@PATCH | PATCH請求 |
請求參數:
註解代碼 | 說明 |
---|---|
@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請求方式。
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;
補充一點哈,GET請求方式,如果攜帶的參數不是以"?num=10&page=1"拼接到接口中(就是不帶?分隔符),那就不用Query註解了,而是使用Path註解:
public interface NewsServicr{
@Get("News/{newsId}")
Call<News> getNews(@Path("newsId") String newsId);
}
@Query與@Path功能相同,但區別明顯不一樣。像@Query的例子,我如果使用@Path來註解,那麼程序就會報錯。這塊要搞清楚!
還有一點,有的url既有“{}”佔位符,又有“?”後面的鍵值對(key-value),那Retrofit既得使用@Query註解又得使用@Path註解,也就是說,兩者可以同時使用。
⑤@Headers
@Headers("apikey:81bf9da930c7f9825a3c3383f1d8d766")
這個很好理解,這個接口需要添加的header:apikey:81bf9da930c7f9825a3c3383f1d8d766@Headers就是把接口的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())
Retrofit支持多種數據解析方式,在使用時注意需要在Gradle添加依賴:
數據解析器 | Gradle依賴 |
---|---|
Gson | com.squareup.retrofit2:converter-gson:2.0.2 |
Jackson | com.squareup.retrofit2:converter-jackson:2.0.2 |
Simple XML | com.squareup.retrofit2:converter-simplexml:2.0.2 |
Protobuf | com.squareup.retrofit2:converter-protobuf:2.0.2 |
Moshi | com.squareup.retrofit2:converter-moshi:2.0.2 |
Wire | com.squareup.retrofit2:converter-wire:2.0.2 |
Scalars | com.squareup.retrofit2:converter-scalars:2.0.2 |
上文代碼中沒有這個方法,但是得知道它的作用,有必要作爲補充知識點
看一下我們的接口返回:
Call<News> news = mApi.getNews("1", "10");
返回的Call<News>可以理解成源生的了,默認就這麼寫。但像很多很多項目都是結合着RXJava來使用這個Retrofit的,那麼這個接口返回就會被定義爲(僞代碼):
Observable<News> news = mApi.getNews("1", "10").subscribeOn(...).observeOn(...);
addCallAdapterFactory()影響的就是第一部分:Call或者Observable。Call類型是Retrofit默認支持的(Retrofit內部有一個DefaultCallAdapterFactory),所以你如果不用RXJava + Retrofit結合使用,那就自動忽略掉這個方法,而如果你想要支持RXJava(就是想把返回值定義爲Observable對象),就需要我們自己用addCallAdapterFactory()添加:addCallAdapterFactory(RxJavaCallAdapterFactory.create())
retrofit = new Retrofit.Builder()
.baseUrl(URL.SERVICE_URL)
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
同理,Retrofit不光支持多種數據解析器,也支持多種網絡請求適配器:Guava、Java8、RXJava ,使用時也需要在Gradle添加依賴:
網絡請求適配器 | Gradle依賴 |
---|---|
Guava | com.squareup.retrofit2:adapter-guava:2.0.2 |
Java8 | com.squareup.retrofit2:adapter-java8:2.0.2 |
RXJava | com.squareup.retrofit2:adapter-rxjava:2.0.2 |
四、發起網絡請求
//對發送請求進行封裝
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的瞭解還比較少,等以後積累了這部分知識再補上。