今天,我们将使用 Square 开发的 **Retrofit ** 库来处理 Android 应用中的 REST API 调用。
安卓的回归
Retrofit 是针对 Android 和 Java 的类型安全的 REST 客户端,旨在使 RESTful 网页服务更容易使用。我们不会进入 Retrofit 1.x 版本的细节,然后直接跳到 Retrofit 2,它有许多新功能和与之前的版本相比的内部 API 更改。Retrofit 2 通过默认杠杆 **OkHttp**作为网络层,并建立在上面。
1compile 'com.squareup.retrofit2:retrofit:2.1.0'
2compile 'com.google.code.gson:gson:2.6.2'
3compile 'com.squareup.retrofit2:converter-gson:2.1.0'
OkHttp 依赖已与 Retrofit 2 依赖一起交付. 如果您希望使用单独的 OkHttp 依赖,则应将 OkHttp 依赖从 Retrofit 2 中排除为:
1compile ('com.squareup.retrofit2:retrofit:2.1.0') {
2 // exclude Retrofit’s OkHttp dependency module and define your own module import
3 exclude module: 'okhttp'
4}
5compile 'com.google.code.gson:gson:2.6.2'
6compile 'com.squareup.retrofit2:converter-gson:2.1.0'
7compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
8compile 'com.squareup.okhttp3:okhttps:3.4.1'
- Logging-interceptor 会生成返回的全部响应的日志字符串
- 还有其他转换器可以将 JSON 解析到所需类型。
- Jackson :
com.squareup.retrofit2:converter-jackson:2.1.0
- Moshi :
com.squareup.retrofit2:converter-moshi:2.1.0
- Protobuf :
com.squareup.retrofit2:converter-protobuf:2.1.0
- Wire :
com.squareup.retrofit2:converter-wire:2.1.0
- 简单的XML :
com.squareup.retrofit2:converter-simplex:2.1.0
在 AndroidManifest.xml 文件中添加访问互联网的权限。
OkHttp 拦截器
接收器是 OkHttp 中存在的强大的机制,可以监控、重写和重新调用呼叫,接收器主要可以分为两类:
- 应用程序拦截器 : 要注册应用程序拦截器,我们需要在
OkHttpClient.Builder
上呼叫addInterceptor()
网络拦截器 : 要注册网络拦截器,请呼叫addNetworkInterceptor()
而不是addInterceptor()
设置 Retrofit 接口
1package com.journaldev.retrofitintro;
2
3import com.journaldev.retrofitintro.pojo.MultipleResource;
4
5import okhttp3.OkHttpClient;
6import okhttp3.logging.HttpLoggingInterceptor;
7import retrofit2.Retrofit;
8import retrofit2.converter.gson.GsonConverterFactory;
9
10class APIClient {
11
12 private static Retrofit retrofit = null;
13
14 static Retrofit getClient() {
15
16 HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
17 interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
18 OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
19
20 retrofit = new Retrofit.Builder()
21 .baseUrl("https://reqres.in")
22 .addConverterFactory(GsonConverterFactory.create())
23 .client(client)
24 .build();
25
26 return retrofit;
27 }
28
29}
上面的代码中的getClient()
方法在设置Retrofit接口时都会被调用。Retrofit为每个HTTP方法提供了注释列表:@GET, @POST, @PUT, @DELETE, @PATCH或 @HEAD
。
1package com.journaldev.retrofitintro;
2
3import com.journaldev.retrofitintro.pojo.MultipleResource;
4import com.journaldev.retrofitintro.pojo.User;
5import com.journaldev.retrofitintro.pojo.UserList;
6
7import retrofit2.Call;
8import retrofit2.http.Body;
9import retrofit2.http.Field;
10import retrofit2.http.FormUrlEncoded;
11import retrofit2.http.GET;
12import retrofit2.http.POST;
13import retrofit2.http.Query;
14
15interface APIInterface {
16
17 @GET("/api/unknown")
18 Call<MultipleResource> doGetListResources();
19
20 @POST("/api/users")
21 Call<User> createUser(@Body User user);
22
23 @GET("/api/users?")
24 Call<UserList> doGetUserList(@Query("page") String page);
25
26 @FormUrlEncoded
27 @POST("/api/users?")
28 Call<UserList> doCreateUserWithField(@Field("name") String name, @Field("job") String job);
29}
在上面的类中,我们已经定义了一些执行HTTP请求与注释的方法。 @GET("/api/unknown")
呼叫 doGetListResources();
. doGetListResources()
是方法的名称. MultipleResource.java
是我们响应对象的模型POJO类别,用于将响应参数绘制到各自的变量。
1package com.journaldev.retrofitintro.pojo;
2
3import com.google.gson.annotations.SerializedName;
4
5import java.util.ArrayList;
6import java.util.List;
7
8public class MultipleResource {
9
10 @SerializedName("page")
11 public Integer page;
12 @SerializedName("per_page")
13 public Integer perPage;
14 @SerializedName("total")
15 public Integer total;
16 @SerializedName("total_pages")
17 public Integer totalPages;
18 @SerializedName("data")
19 public List<Datum> data = null;
20
21 public class Datum {
22
23 @SerializedName("id")
24 public Integer id;
25 @SerializedName("name")
26 public String name;
27 @SerializedName("year")
28 public Integer year;
29 @SerializedName("pantone_value")
30 public String pantoneValue;
31
32 }
33}
@SerializedName
annotation is used to specify the name of the field that's in the JSON Response. Preview the POJO class and copy it into your Android Studio Project Structure. The POJO classes are wrapped into a typed Retrofit
Call
class. Note: A JSONArray is serialised a List of Objects in the POJO classes Method Parameters : There are a wide variety of possible options of parameters to pass inside a method:
@Body
- 将 Java 对象发送为请求体@Url
- 使用动态 URL@Query
- 我们可以简单地添加 @Query 和查询参数名称的方法参数,描述类型。 若要使用 URL 编码查询,请使用表单:@Query(值 = "auth_token",编码 = true) String auth_token
@Field
- 以 urlencoded 形式发送数据。
** 注意**: @Field 需要强制参数. 如果 @Field 是可选的,我们可以使用 @Query 代替并传递一个 null 值。
Retrofit Android 示例项目结构
The pojo package defines four model classes for each of the API endpoint responses defined in the APIInterface.java class.
User.java
1package com.journaldev.retrofitintro.pojo;
2
3import com.google.gson.annotations.SerializedName;
4
5public class User {
6
7 @SerializedName("name")
8 public String name;
9 @SerializedName("job")
10 public String job;
11 @SerializedName("id")
12 public String id;
13 @SerializedName("createdAt")
14 public String createdAt;
15
16 public User(String name, String job) {
17 this.name = name;
18 this.job = job;
19 }
20
21}
上面的类用于创建createUser()
方法UserList.java
的响应体。
1package com.journaldev.retrofitintro.pojo;
2
3import com.google.gson.annotations.SerializedName;
4
5import java.util.ArrayList;
6import java.util.List;
7
8public class UserList {
9
10 @SerializedName("page")
11 public Integer page;
12 @SerializedName("per_page")
13 public Integer perPage;
14 @SerializedName("total")
15 public Integer total;
16 @SerializedName("total_pages")
17 public Integer totalPages;
18 @SerializedName("data")
19 public List<Datum> data = new ArrayList();
20
21 public class Datum {
22
23 @SerializedName("id")
24 public Integer id;
25 @SerializedName("first_name")
26 public String first_name;
27 @SerializedName("last_name")
28 public String last_name;
29 @SerializedName("avatar")
30 public String avatar;
31
32 }
33}
创建用户响应.java
1package com.journaldev.retrofitintro.pojo;
2
3import com.google.gson.annotations.SerializedName;
4
5public class CreateUserResponse {
6
7 @SerializedName("name")
8 public String name;
9 @SerializedName("job")
10 public String job;
11 @SerializedName("id")
12 public String id;
13 @SerializedName("createdAt")
14 public String createdAt;
15}
MainActivity.java
是我们在界面类中定义的每个 API 终端点的呼叫,并在 Toast/TextView 中显示每个字段。
1package com.journaldev.retrofitintro;
2
3import android.support.v7.app.AppCompatActivity;
4import android.os.Bundle;
5import android.util.Log;
6import android.widget.TextView;
7import android.widget.Toast;
8
9import com.journaldev.retrofitintro.pojo.CreateUserResponse;
10import com.journaldev.retrofitintro.pojo.MultipleResource;
11import com.journaldev.retrofitintro.pojo.User;
12import com.journaldev.retrofitintro.pojo.UserList;
13
14import java.util.List;
15
16import retrofit2.Call;
17import retrofit2.Callback;
18import retrofit2.Response;
19
20public class MainActivity extends AppCompatActivity {
21
22 TextView responseText;
23 APIInterface apiInterface;
24
25 @Override
26 protected void onCreate(Bundle savedInstanceState) {
27 super.onCreate(savedInstanceState);
28 setContentView(R.layout.activity_main);
29 responseText = (TextView) findViewById(R.id.responseText);
30 apiInterface = APIClient.getClient().create(APIInterface.class);
31
32 /**
33 GET List Resources
34 **/
35 Call<MultipleResource> call = apiInterface.doGetListResources();
36 call.enqueue(new Callback<MultipleResource>() {
37 @Override
38 public void onResponse(Call<MultipleResource> call, Response<MultipleResource> response) {
39
40 Log.d("TAG",response.code()+"");
41
42 String displayResponse = "";
43
44 MultipleResource resource = response.body();
45 Integer text = resource.page;
46 Integer total = resource.total;
47 Integer totalPages = resource.totalPages;
48 List<MultipleResource.Datum> datumList = resource.data;
49
50 displayResponse += text + " Page\n" + total + " Total\n" + totalPages + " Total Pages\n";
51
52 for (MultipleResource.Datum datum : datumList) {
53 displayResponse += datum.id + " " + datum.name + " " + datum.pantoneValue + " " + datum.year + "\n";
54 }
55
56 responseText.setText(displayResponse);
57
58 }
59
60 @Override
61 public void onFailure(Call<MultipleResource> call, Throwable t) {
62 call.cancel();
63 }
64 });
65
66 /**
67 Create new user
68 **/
69 User user = new User("morpheus", "leader");
70 Call<User> call1 = apiInterface.createUser(user);
71 call1.enqueue(new Callback<User>() {
72 @Override
73 public void onResponse(Call<User> call, Response<User> response) {
74 User user1 = response.body();
75
76 Toast.makeText(getApplicationContext(), user1.name + " " + user1.job + " " + user1.id + " " + user1.createdAt, Toast.LENGTH_SHORT).show();
77
78 }
79
80 @Override
81 public void onFailure(Call<User> call, Throwable t) {
82 call.cancel();
83 }
84 });
85
86 /**
87 GET List Users
88 **/
89 Call<UserList> call2 = apiInterface.doGetUserList("2");
90 call2.enqueue(new Callback<UserList>() {
91 @Override
92 public void onResponse(Call<UserList> call, Response<UserList> response) {
93
94 UserList userList = response.body();
95 Integer text = userList.page;
96 Integer total = userList.total;
97 Integer totalPages = userList.totalPages;
98 List<UserList.Datum> datumList = userList.data;
99 Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();
100
101 for (UserList.Datum datum : datumList) {
102 Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
103 }
104
105 }
106
107 @Override
108 public void onFailure(Call<UserList> call, Throwable t) {
109 call.cancel();
110 }
111 });
112
113 /**
114 POST name and job Url encoded.
115 **/
116 Call<UserList> call3 = apiInterface.doCreateUserWithField("morpheus","leader");
117 call3.enqueue(new Callback<UserList>() {
118 @Override
119 public void onResponse(Call<UserList> call, Response<UserList> response) {
120 UserList userList = response.body();
121 Integer text = userList.page;
122 Integer total = userList.total;
123 Integer totalPages = userList.totalPages;
124 List<UserList.Datum> datumList = userList.data;
125 Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();
126
127 for (UserList.Datum datum : datumList) {
128 Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
129 }
130
131 }
132
133 @Override
134 public void onFailure(Call<UserList> call, Throwable t) {
135 call.cancel();
136 }
137 });
138
139 }
140}
「apiInterface = APIClient.getClient().create(APIInterface.class);」用于实时化APIClient。 为了将模型类对我们所使用的响应进行映射:「MultipleResource resource = response.body();」运行应用程序将调用每个终端点并显示一个 Toast消息。 这将结束Retrofit android示例教程。 您可以从下面的链接下载Android Retrofit示例项目。