Поиск по сайту:

Учебное пособие по модернизации Android


Добро пожаловать в учебник по модернизации Android. Сегодня мы будем использовать библиотеку Retrofit, разработанную Square, для обработки вызовов REST API в нашем приложении для Android.

Модернизация Android

Retrofit — это типобезопасный клиент REST для Android и Java, цель которого — упростить использование веб-сервисов RESTful. Мы не будем вдаваться в детали версий Retrofit 1.x и сразу перейдем к Retrofit 2, которая имеет множество новых функций и измененный внутренний API по сравнению с предыдущими версиями. Retrofit 2 по умолчанию использует OkHttp в качестве сетевого уровня и построен на его основе. Retrofit автоматически сериализует ответ JSON, используя POJO (обычный старый объект Java), который должен быть определен заранее для структуры 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, вы должны исключить зависимость OkHttp из Retrofit 2 как:

compile ('com.squareup.retrofit2:retrofit:2.1.0') {  
  // exclude Retrofit’s OkHttp dependency module and define your own module import
  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 в нужный тип. Некоторые из них перечислены ниже.

  1. Джексон: com.squareup.retrofit2:converter-jackson:2.1.0
  2. Моши: com.squareup.retrofit2:converter-moshi:2.1.0
  3. Protobuf: com.squareup.retrofit2:converter-protobuf:2.1.0
  4. Провод: com.squareup.retrofit2:converter-wire:2.1.0
  5. Простой XML: com.squareup.retrofit2:converter-simplexml:2.1.0

Добавьте разрешение на доступ в Интернет в файле AndroidManifest.xml.

Перехватчики OkHttp

Перехватчики — это мощный механизм, представленный в OkHttp, который может отслеживать, перезаписывать и повторять вызовы. Перехватчики можно разделить на две категории:

  • Перехватчики приложений. Чтобы зарегистрировать перехватчик приложений, нам нужно вызвать addInterceptor() в OkHttpClient.Builder
  • Сетевые перехватчики: чтобы зарегистрировать сетевой перехватчик, вызовите addNetworkInterceptor() вместо addInterceptor()

Настройка интерфейса модернизации

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 — это класс Model 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;

    }
}

  • @Body — отправляет объекты Java в виде тела запроса.
  • @Url – используйте динамические URL-адреса.
  • @Query — мы можем просто добавить параметр метода с помощью @Query и имя параметра запроса, описывающее тип. Для URL-кодирования запроса используйте форму: @Query(value=auth_token,encoded=true) String auth_token
  • @Field — отправлять данные в формате form-urlencoded. Для этого требуется аннотация @FormUrlEncoded, прикрепленная к методу. Параметр @Field работает только с POST

Примечание. Вместо этого используйте @Query и передайте нулевое значение.

Пример структуры проекта модернизации Android

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. Чтобы сопоставить класс Model с ответом, мы используем: MultipleResource resource=response.body(); Запуск приложения будет вызывать каждую из конечных точек и отображать для них всплывающее сообщение соответственно. На этом учебник по дооснащению Android заканчивается. Вы можете скачать пример проекта Android Retrofit по ссылке ниже.

Скачать пример проекта модернизации Android