深入剖析Retrofit系列(一)來自官方的Retrofit開發手冊(中英互譯)

亓春傑發表於2018-08-17

Introduction

Retrofit turns your HTTP API into a Java interface.

Retrofit將你的Http API轉換為了Java介面。
public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}
複製程式碼

The Retrofit class generates an implementation of the GitHubService interface.

Retrofit類會自動生成GithubService介面的實現。
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

GitHubService service = retrofit.create(GitHubService.class);
複製程式碼

Each Call from the created GitHubService can make a synchronous or asynchronous HTTP request to the remote webserver.

GithubService上的每一個Call, 都會生成一個同步或非同步的Http請求來訪問遠端伺服器。
Call<List<Repo>> repos = service.listRepos("octocat");
複製程式碼

Use annotations to describe the HTTP request:

URL parameter replacement and query parameter support Object conversion to request body (e.g., JSON, protocol buffers) Multipart request body and file upload

使用註解來描述Http請求:
.URL引數替換和查詢引數支援
.物件轉換為請求體
.Multipart請求體和檔案上傳

API定義

Annotations on the interface methods and its parameters indicate how a request will be handled.

介面方法和它的引數註解指定了如何處理一個請求。

請求方法

Every method must have an HTTP annotation that provides the request method and relative URL. There are five built-in annotations: GET, POST, PUT, DELETE, and HEAD. The relative URL of the resource is specified in the annotation.

每一個方法必須提供一個提供了相對路徑URL和請求方法的Http註解。 有5個內建註釋: GET, POST, PUT, DELETE, 和HEAD。 相對路徑URL是在註解中指定的。
@GET("users/list")
複製程式碼

You can also specify query parameters in the URL.

你也可以在URL中指定查詢引數。
@GET("users/list?sort=desc")
複製程式碼

URL操作

A request URL can be updated dynamically using replacement blocks and parameters on the method. A replacement block is an alphanumeric string surrounded by { and }. A corresponding parameter must be annotated with @Path using the same string.

一個請求URL是可以通過方法上的替換塊和引數來動態替換的。替換塊是由{,}包圍的數字和字串。 對應的引數裡面必須使用帶相同字串的@Path註解來填充。
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId);
複製程式碼

Query parameters can also be added.

也可以新增Query引數
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @Query("sort") String sort);
複製程式碼

For complex query parameter combinations a Map can be used.

對於複雜的查詢引數組合, 可以使用Map。
@GET("group/{id}/users")
Call<List<User>> groupList(@Path("id") int groupId, @QueryMap Map<String, String> options);
複製程式碼

RequestBody

An object can be specified for use as an HTTP request body with the @Body annotation.

可以使用@Body註解來指定一個物件作為Http請求的引數。
@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.

物件會使用設定在Retrofit上的converter進行轉換。 如果沒有新增converter, 只能只能使用RequestBody。

FORM ENCODED AND MULTIPART

Methods can also be declared to send form-encoded and multipart data.

Form-encoded data is sent when @FormUrlEncoded is present on the method. Each key-value pair is annotated with @Field containing the name and the object providing the value.

也可以在方法上新增form-encoded 和 multipart資料。
當在方法上新增@FormUrlEncoded註解, 將會傳送Form-encoded資料。 每個鍵值對都包含名稱的@Filed註解來提供資料。
@FormUrlEncoded
@POST("user/edit")
Call<User> updateUser(@Field("first_name") String first, @Field("last_name") String last);
複製程式碼

Multipart requests are used when @Multipart is present on the method. Parts are declared using the @Part annotation.

如果再方法上新增了@Multipart註解, Multipart請求會被使用。 Parts是使用@Parts來定義的。
@Multipart
@PUT("user/photo")
Call<User> updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);
複製程式碼

Multipart parts use one of Retrofit's converters or they can implement RequestBody to handle their own serialization.

Multipart 部分使用Retrofit的轉換器, 或者它們可以通過自己的RequestBody來實現自己的序列。

Header操作

You can set static headers for a method using the @Headers annotation.

你可以使用@Headers來設定靜態的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);
複製程式碼

Note that headers do not overwrite each other. All headers with the same name will be included in the request.

A request Header can be updated dynamically using the @Header annotation. A corresponding parameter must be provided to the @Header. If the value is null, the header will be omitted. Otherwise, toString will be called on the value, and the result used.

注意: headers不會相互覆蓋, 所有加入的同名headers都會被新增到請求中。
一個請求的header可以使用@Header動態修改。 必須給@Header提供相應的引數。 如果值是空的, header將不會新增到請求。 否則, value的toString()會被呼叫, 並使用其結果。
@GET("user")
Call<User> getUser(@Header("Authorization") String authorization)
複製程式碼

Similar to query parameters, for complex header combinations, a Map can be used.

和Query引數類似, 對於複雜的header組合, 請使用Map。
@GET("user")
Call<User> getUser(@HeaderMap Map<String, String> headers)
複製程式碼

Headers that need to be added to every request can be specified using an OkHttp interceptor.

如果想統一新增headers, 請使用OkHttp的攔截器。

同步 VS 非同步

Call instances can be executed either synchronously or asynchronously. Each instance can only be used once, but calling clone() will create a new instance that can be used.

On Android, callbacks will be executed on the main thread. On the JVM, callbacks will happen on the same thread that executed the HTTP request.

Call物件既可以同步執行, 也可以非同步執行。 每個物件只能使用一次, 但是呼叫clone()可以建立一個新物件來使用。
在Android中, 會在主執行緒執行回撥。 在JVM中, 回撥會發生在和請求同一個執行緒中。

Retrofit配置

Retrofit is the class through which your API interfaces are turned into callable objects. By default, Retrofit will give you sane defaults for your platform but it allows for customization.

Retrofit是將API介面轉換為可呼叫物件的類。 預設情況下, Retrofit將會為你的平臺提供合理的預設值,但是它允許自定義。

轉換器

By default, Retrofit can only deserialize HTTP bodies into OkHttp's ResponseBody type and it can only accept its RequestBody type for @Body.

預設情況下, Retrofit只能將請求主體反序列化為OkHttp的ResponseBody型別。 它的@Body只能接收RequestBody型別。

Converters can be added to support other types. Six sibling modules adapt popular serialization libraries for your convenience. 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

你可以新增Converters來支援其他型別。 下面有6個主流的的反序列化庫供您使用:
Gson, Jackson, Moshi, Protobuf, Wire, SimpleXML, Scalars。

Here's an example of using the GsonConverterFactory class to generate an implementation of the GitHubService interface which uses Gson for its deserialization.

下面是一個使用GsonConverterFactory類生成GitHubService介面實現的示例,該介面使用Gson進行反序列化。
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

GitHubService service = retrofit.create(GitHubService.class);
複製程式碼

自定義轉換器

If you need to communicate with an API that uses a content-format that Retrofit does not support out of the box (e.g. YAML, txt, custom format) or you wish to use a different library to implement an existing format, you can easily create your own converter. Create a class that extends the Converter.Factory class and pass in an instance when building your adapter.

如果你需要使用Retrofit不支援的API, 或你希望使用一個不同的庫來實現已經存在的格式, 你可以輕鬆的建立你自己的Converter。 建立一個類繼承Converter.Factory,並在你構建介面卡的時候傳進一個物件。

引入

MAVEN

<dependency>
  <groupId>com.squareup.retrofit2</groupId>
  <artifactId>retrofit</artifactId>
  <version>(insert latest version)</version>
</dependency>
複製程式碼

GRADLE

implementation 'com.squareup.retrofit2:retrofit:(insert latest version)'
複製程式碼
注意事項: Retrofit需要最低Java7 和 Android 2.3。
如果你正在使用R8, 或者ProGuard
# Retain generic type information for use by reflection by converters and adapters.
-keepattributes Signature

# Retain service method parameters when optimizing.
-keepclassmembers,allowshrinking,allowobfuscation interface * {
    @retrofit2.http.* <methods>;
}

# Ignore annotation used for build tooling.
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement

# Ignore JSR 305 annotations for embedding nullability information.
-dontwarn javax.annotation.**
複製程式碼

官方解釋結束。 最終發現, Retrofit只做了一件事, 就是把Request的資料轉換為Response返回數, 並簡化了請求和返回的過程。

相關文章