欢迎来到Retrofit Android示例教程。今天我们将使用由Square开发的Retrofit库来处理我们的Android应用程序中的REST API调用。
Android Retrofit
Retrofit是用于Android和Java的类型安全的REST客户端,旨在更轻松地消费RESTful web服务。我们将不详细介绍Retrofit 1.x版本,并直接跳到与以前版本相比具有许多新功能和更改的Retrofit 2。Retrofit 2默认使用OkHttp作为网络层,并在其之上构建。Retrofit会自动使用POJO(Plain Old Java Object)来序列化JSON响应,该POJO必须事先定义好JSON结构。为了将JSON序列化,我们需要一个转换器将其首先转换为Gson。我们需要在build.grade
文件中添加以下依赖项。
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
OkHttp依赖项已经随Retrofit 2依赖项一起提供。如果您希望使用单独的OkHttp依赖项,您应该从Retrofit 2中排除OkHttp依赖项,如下所示:
compile ('com.squareup.retrofit2:retrofit:2.1.0') {
// 排除Retrofit的OkHttp依赖模块并定义您自己的模块导入
exclude module: 'okhttp'
}
compile 'com.google.code.gson:gson:2.6.2'
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.4.1'
compile '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
- Simple XML:
com.squareup.retrofit2:converter-simplexml:2.1.0
在AndroidManifest.xml文件中添加访问互联网的权限。
OkHttp拦截器
拦截器是OkHttp中的一种强大机制,可以监视、重写和重试请求。拦截器主要分为两类:
- 应用拦截器:要注册一个应用拦截器,我们需要在
OkHttpClient.Builder
上调用addInterceptor()
- 网络拦截器:要注册一个网络拦截器,需要调用
addNetworkInterceptor()
而不是addInterceptor()
设置Retrofit接口
package com.journaldev.retrofitintro;
import com.journaldev.retrofitintro.pojo.MultipleResource;
import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
class APIClient {
private static Retrofit retrofit = null;
static Retrofit getClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
retrofit = new Retrofit.Builder()
.baseUrl("https://reqres.in")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
return retrofit;
}
}
上述代码中的getClient()
方法将在设置Retrofit接口时每次调用。Retrofit为每个HTTP方法提供了一组注解:@GET、@POST、@PUT、@DELETE、@PATCH或@HEAD
。让我们看看我们的APIInterface.java
类是什么样的。
package com.journaldev.retrofitintro;
import com.journaldev.retrofitintro.pojo.MultipleResource;
import com.journaldev.retrofitintro.pojo.User;
import com.journaldev.retrofitintro.pojo.UserList;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;
interface APIInterface {
@GET("/api/unknown")
Call<MultipleResource> doGetListResources();
@POST("/api/users")
Call<User> createUser(@Body User user);
@GET("/api/users?")
Call<UserList> doGetUserList(@Query("page") String page);
@FormUrlEncoded
@POST("/api/users?")
Call<UserList> doCreateUserWithField(@Field("name") String name, @Field("job") String job);
}
在上述类中,我们定义了一些使用注解执行HTTP请求的方法。@GET("/api/unknown")
调用doGetListResources();
。doGetListResources()
是方法名。MultipleResource.java
是我们响应对象的模型POJO类,用于将响应参数映射到相应的变量。这些POJO类充当方法的返回类型。下面是一个简单的MultipleResources.java
的POJO类。
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
public class MultipleResource {
@SerializedName("page")
public Integer page;
@SerializedName("per_page")
public Integer perPage;
@SerializedName("total")
public Integer total;
@SerializedName("total_pages")
public Integer totalPages;
@SerializedName("data")
public List<Datum> data = null;
public class Datum {
@SerializedName("id")
public Integer id;
@SerializedName("name")
public String name;
@SerializedName("year")
public Integer year;
@SerializedName("pantone_value")
public String pantoneValue;
}
}
@SerializedName
注解用于指定在JSON响应中的字段名称。预览POJO类并将其复制到Android Studio项目结构中。POJO类封装在一个带类型的Retrofit
Call
类中。注意:JSONArray在POJO类中被序列化为对象列表。方法参数:在方法内部传递参数有多种可能的选项:
@Body
– 将Java对象作为请求体发送。@Url
– 使用动态URL。@Query
– 我们可以简单地添加一个带有@Query和一个查询参数名称的方法参数,描述类型。要对查询进行URL编码,请使用以下形式:@Query(value = "auth_token",encoded = true) String auth_token
@Field
– 以表单-urlencoded形式发送数据。这需要一个附加在方法上的@FormUrlEncoded
注解。@Field
参数仅适用于POST请求
注意:@Field需要一个必需的参数。在@Field是可选的情况下,我们可以使用@Query代替,并传递一个null值。
Retrofit Android示例项目结构
pojo包定义了每个API端点响应的四个模型类,这些类在APIInterface.java类中定义。
User.java
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
public class User {
@SerializedName("name")
public String name;
@SerializedName("job")
public String job;
@SerializedName("id")
public String id;
@SerializedName("createdAt")
public String createdAt;
public User(String name, String job) {
this.name = name;
this.job = job;
}
}
上述类用于为createUser()
方法创建响应体UserList.java
。
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
import java.util.ArrayList;
import java.util.List;
public class UserList {
@SerializedName("page")
public Integer page;
@SerializedName("per_page")
public Integer perPage;
@SerializedName("total")
public Integer total;
@SerializedName("total_pages")
public Integer totalPages;
@SerializedName("data")
public List<Datum> data = new ArrayList();
public class Datum {
@SerializedName("id")
public Integer id;
@SerializedName("first_name")
public String first_name;
@SerializedName("last_name")
public String last_name;
@SerializedName("avatar")
public String avatar;
}
}
CreateUserResponse.java
package com.journaldev.retrofitintro.pojo;
import com.google.gson.annotations.SerializedName;
public class CreateUserResponse {
@SerializedName("name")
public String name;
@SerializedName("job")
public String job;
@SerializedName("id")
public String id;
@SerializedName("createdAt")
public String createdAt;
}
在MainActivity.java
中,我们调用接口类中定义的每个API端点,并在Toast/TextView中显示每个字段。
package com.journaldev.retrofitintro;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.journaldev.retrofitintro.pojo.CreateUserResponse;
import com.journaldev.retrofitintro.pojo.MultipleResource;
import com.journaldev.retrofitintro.pojo.User;
import com.journaldev.retrofitintro.pojo.UserList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
TextView responseText;
APIInterface apiInterface;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
responseText = (TextView) findViewById(R.id.responseText);
apiInterface = APIClient.getClient().create(APIInterface.class);
/**
GET List Resources
**/
Call<MultipleResource> call = apiInterface.doGetListResources();
call.enqueue(new Callback<MultipleResource>() {
@Override
public void onResponse(Call<MultipleResource> call, Response<MultipleResource> response) {
Log.d("TAG",response.code()+"");
String displayResponse = "";
MultipleResource resource = response.body();
Integer text = resource.page;
Integer total = resource.total;
Integer totalPages = resource.totalPages;
List<MultipleResource.Datum> datumList = resource.data;
displayResponse += text + " Page\n" + total + " Total\n" + totalPages + " Total Pages\n";
for (MultipleResource.Datum datum : datumList) {
displayResponse += datum.id + " " + datum.name + " " + datum.pantoneValue + " " + datum.year + "\n";
}
responseText.setText(displayResponse);
}
@Override
public void onFailure(Call<MultipleResource> call, Throwable t) {
call.cancel();
}
});
/**
Create new user
**/
User user = new User("morpheus", "leader");
Call<User> call1 = apiInterface.createUser(user);
call1.enqueue(new Callback<User>() {
@Override
public void onResponse(Call<User> call, Response<User> response) {
User user1 = response.body();
Toast.makeText(getApplicationContext(), user1.name + " " + user1.job + " " + user1.id + " " + user1.createdAt, Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<User> call, Throwable t) {
call.cancel();
}
});
/**
GET List Users
**/
Call<UserList> call2 = apiInterface.doGetUserList("2");
call2.enqueue(new Callback<UserList>() {
@Override
public void onResponse(Call<UserList> call, Response<UserList> response) {
UserList userList = response.body();
Integer text = userList.page;
Integer total = userList.total;
Integer totalPages = userList.totalPages;
List<UserList.Datum> datumList = userList.data;
Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();
for (UserList.Datum datum : datumList) {
Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<UserList> call, Throwable t) {
call.cancel();
}
});
/**
POST name and job Url encoded.
**/
Call<UserList> call3 = apiInterface.doCreateUserWithField("morpheus","leader");
call3.enqueue(new Callback<UserList>() {
@Override
public void onResponse(Call<UserList> call, Response<UserList> response) {
UserList userList = response.body();
Integer text = userList.page;
Integer total = userList.total;
Integer totalPages = userList.totalPages;
List<UserList.Datum> datumList = userList.data;
Toast.makeText(getApplicationContext(), text + " page\n" + total + " total\n" + totalPages + " totalPages\n", Toast.LENGTH_SHORT).show();
for (UserList.Datum datum : datumList) {
Toast.makeText(getApplicationContext(), "id : " + datum.id + " name: " + datum.first_name + " " + datum.last_name + " avatar: " + datum.avatar, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<UserList> call, Throwable t) {
call.cancel();
}
});
}
}
apiInterface = APIClient.getClient().create(APIInterface.class);
用于实例化APIClient。为了将模型类映射到响应中,我们使用:MultipleResource resource = response.body();
运行应用程序将调用每个端点,并相应地显示Toast消息。这结束了Retrofit android示例教程。您可以从下面的链接下载Android Retrofit示例项目。
Source:
https://www.digitalocean.com/community/tutorials/retrofit-android-example-tutorial