Добро пожаловать в руководство по примеру Retrofit Android. Сегодня мы будем использовать библиотеку Retrofit, разработанную компанией Square, для обработки вызовов REST API в нашем приложении Android.
Retrofit Android
Retrofit – это типобезопасный REST-клиент для Android и Java, который призван упростить потребление служб веб-сервисов RESTful. Мы не будем вдаваться в детали версий Retrofit 1.x и перейдем непосредственно к Retrofit 2, который имеет много новых функций и измененный внутренний API по сравнению с предыдущими версиями. Retrofit 2 по умолчанию использует OkHttp в качестве сетевого слоя и построен на его основе. Retrofit автоматически сериализует JSON-ответ с использованием POJO (Plain Old Java Object), который должен быть предварительно определен для структуры JSON. Для сериализации JSON нам нужен конвертер для преобразования его сначала в Gson. Мы должны добавить следующие зависимости в наш файл build.gradle
.
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, вы должны исключить зависимость OkHttp из Retrofit 2, как показано ниже:
compile ('com.squareup.retrofit2:retrofit:2.1.0') {
// исключить модуль зависимости OkHttp Retrofit и определить собственный модуль импорта
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'
- Логгирование-интерсептор генерирует строку журнала для всего ответа, который возвращается.
- Существуют и другие конвертеры для разбора 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, который может отслеживать, переписывать и повторять вызовы. Перехватчики можно разделить на две основные категории:
- Перехватчики приложения : Чтобы зарегистрировать перехватчик приложения, нам нужно вызвать
addInterceptor()
наOkHttpClient.Builder
- Сетевые перехватчики : Чтобы зарегистрировать сетевой перехватчик, используйте
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 действуют как тип возвращаемого метода. Простой класс POJO для MultipleResources.java
приведен ниже.
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
– отправка данных в формате form-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
мы вызываем каждый из определенных в классе Interface конечных точек 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. Для сопоставления класса Model с ответом мы используем: MultipleResource resource = response.body();
Запуск приложения вызовет каждую из конечных точек и отобразит для них сообщение Toast соответственно. Это завершает пример учебника по Retrofit для Android. Вы можете скачать проект примера Android Retrofit по ссылке ниже.
Source:
https://www.digitalocean.com/community/tutorials/retrofit-android-example-tutorial