Android開源網路框架Retrofit(入門篇)
Restful風格介面基本成了業界主流,Retrofit框架也大火特火,最近專案中也決定更新換代,採用Retrofit。本著學習之餘,也對接下來的學習者有一些幫助,於是寫了本文,主要的內容是對官網內容的一個翻譯和補充解釋。
plus:本文假設你對於基本的HTTP協議有所瞭解。
一、Retrofit簡介
Retrofit內部使用OKhttp來進行網路請求, 會把網路請求轉化為一個java介面,使用了編譯階段的註解提高開發效率。如下,在開發中把網路請求定義在一個專門的java介面中
public interface GitHubService {
@GET("users/{user}/repos" )
Call<List<Repo>> listRepos(@Path("user") String user);
}
通過Retrofit為此介面生成一個實現,程式碼如下
//定製OKHttpClient
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.readTimeout(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.connectTimeout(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS )
.writeTimeout(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
.build();
//例項化 Retrofit
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.client(okHttpClient)
.build();
//生成實現類
GitHubService service = retrofit.create(GitHubService.class );
通過生成的GitHubService,開發者可以使用同步或者非同步的方式去請求網路介面。
Call<List<Repo>> repos = service.listRepos("octocat");
Retrofit 使用註解來描述HTTP介面,提升開發效率,它有如下特性:
- URL引數動態替換、動態位址列引數。
- 物件能動態轉化成RequestBody,比如 JSON和protocol buffers。
- 支援Multipart RequestBody(對這個不瞭解的,看下這篇博文)
- 支援檔案上傳。
上述特性,具體看下面的章節就明白了。
二、Retrofit的註解用法詳解
1. 網路介面的宣告
在Retrofit中,每個網路介面都必須有一個註解,網路介面上的註解表明了型別、Url訪問路徑。這裡有五個內建的註解: GET, POST, PUT, DELETE, and HEAD。如下示例,聲明瞭一個簡單的GET網路介面,其相對路徑是users/list。
@GET("users/list")
跟傳統一樣,你可以在路徑中加上引數。
@GET("users/list?sort=desc")
2. URL相關的註解
相對路徑中可以宣告動態引數,用 {str1} 程式碼 表示,在接口裡面通過 @Path(“str1”) 修飾相應用於動態替換的引數。
具體用法如下展示,其中groupId的值會動態替換掉訪問路徑中的{id}。
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
位址列引數也是可以使用 @Query(“str”)加上,效果就是在訪問URL後面動態加上 @Query(“str”)標識的引數
如下方法,最終的URL會是這樣:group/{id}/users/?sort=xxx
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
如果是想加上很多個位址列引數,Retrofit提供了map的方式,map裡面的多個鍵值對會依次加入到URL後邊。
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
3. Request Body 相關注解
上文已經提到,物件能動態轉化成RequestBody,具體是要在物件前使用 @Body註解。如下程式碼所示,User物件會被轉化成Body。
@POST("users/new")
Call<User> createUser(@Body User user);
The object will also be converted using a converter specified on the Retrofit instance. If no converter is added, only RequestBody can be used.
物件轉化為Body的方式是Retrofit預設提供的一個轉化器,你也可以自己建立一個轉換器,在Retrofit例項化的時候進行指定。
4. 表單和使用Multipart Body
Retrofit使用註解 @FormUrlEncoded 來表示使用表單,表單裡面相應的欄位在介面引數前使用 @Field(“XXX”)標識,括號裡面是key值。
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
Multipart Body直接使用 @Multipart 在介面方法上標識. Body中的Parts 直接使用 @Part 標識。
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
同上文所說,Multipart parts也採用了Retrofit預設的序列化轉換器,如果你希望自己定義序列化,可以繼承RequestBody類,重寫序列化方法。
5. Retrofit設定請求頭的相關注解
你可以為一些方法設定請求頭欄位,這個需使用 @Headers 註解
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call<List<Widget>> widgetList();
@Headers({
"Accept: application/vnd.github.v3.full+json",
"User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call<User> getUser(@Path("username") String username);
請求頭欄位也可以被動態改變,在介面引數前加上 @Header就可以了。
額外說明:如果該引數傳入為null,那麼請求頭的該欄位會被刪除。該欄位的引數型別可以不是String型別,Retrofit最終會呼叫該引數的toString()方法,得到的值作為請求頭該欄位的值。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
一路看下來,可能有讀者會問了,難道我需要為每個介面方法都設定一遍請求頭嗎?
不是的,對於所有介面都要用到的請求頭,可以通過 Okhttp攔截器統一設定。
三、Retrofit 的配置
通過上述描述,大家應該已經發現,Retrofit提供的功能就是把網路請求變成一個可呼叫的例項物件,這個物件裡面是Restful風格的各個網路請求介面。Retrofit提供了一些好的註解,幫我們減輕了封裝網路模組的工作。
Retrofit預設會為我們的平臺提供合適的,健壯的預設配置,但是這些配置我們也是可以自己定製的。
預設情況下,Retrofit 只能 把 HTTP Body型別 反序列化成 OKhttp的 ResponseBody型別,而且接口裡面預設接受的是 RequestBody型別,這個上文已經講過。
Retrofit支援配置其他的轉換器,來支援其他的型別,官網提供瞭如下6個可動態配置的libraries,需要哪個你就在Gradle裡面配置進來。
- Gson: com.squareup.retrofit2:converter-gson
- Jackson: com.squareup.retrofit2:converter-jackson
- Moshi: com.squareup.retrofit2:converter-moshi
- Protobuf: com.squareup.retrofit2:converter-protobuf
- Wire: com.squareup.retrofit2:converter-wire
- Simple XML: com.squareup.retrofit2:converter-simplexml
- Scalars (primitives, boxed, and String): com.squareup.retrofit2:converter-scalars
下面是官網的例子,展示瞭如何使用其他的轉換器,這個只需要在建立Retrofit物件的時候動態傳入轉換器就可以了。下面例子使用了Gson作為反序列化工具。
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://api.github.com")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitHubService service = retrofit.create(GitHubService.class);
如果官網提供的轉換器無法滿足你,你可以自己繼承 Converter.Factory類,擴充套件你需要的功能
四、使用Retrofit
1. GRADLE配置
compile 'com.squareup.retrofit2:retrofit:2.1.0'
注意:Retrofit僅支援 Java 7 及 Android 2.3 以上版本。
2. PROGUARD配置
如果你的專案使用了混淆,請將如下程式碼新增到proguards-rules 資料夾當中。
# Platform calls Class.forName on types which do not exist on Android to determine platform.
-dontnote retrofit2.Platform
# Platform used when running on RoboVM on iOS. Will not be used at runtime.
-dontnote retrofit2.Platform$IOS$MainThreadExecutor
# Platform used when running on Java 8 VMs. Will not be used at runtime.
-dontwarn retrofit2.Platform$Java8
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature
# Retain declared checked exceptions for use by a Proxy instance.
-keepattributes Exceptions