Въведение в модернизацията

1. Общ преглед

Модернизацията е безопасен за типа HTTP клиент за Android и Java - разработен от Square (Dagger, Okhttp).

В тази статия ще обясним как да използваме модернизацията, с акцент върху най-интересните й характеристики. По-забележително ще обсъдим синхронния и асинхронния API, как да го използваме с удостоверяване, регистриране и някои добри практики за моделиране.

2. Настройка на Примера

Ще започнем с добавяне на библиотеката за модернизация и конвертора на Gson:

 com.squareup.retrofit2 retrofit 2.3.0   com.squareup.retrofit2 converter-gson 2.3.0 

За най-новите версии погледнете Retrofit и converter-gson в хранилището на Maven Central.

3. API моделиране

Модернизираните модели REST крайни точки като Java интерфейси, което ги прави много лесни за разбиране и консумация.

Ще моделираме потребителския API от GitHub; това има GET крайна точка, която връща това във формат JSON:

{ login: "mojombo", id: 1, url: "//api.github.com/users/mojombo", ... }

Модернизацията работи чрез моделиране на основен URL адрес и като интерфейсите връщат обектите от крайната точка REST.

За целите на простотата ще вземем малка част от JSON, като моделираме нашия потребителски клас, който ще вземе стойностите, когато ги получим:

public class User { private String login; private long id; private String url; // ... // standard getters an setters }

Виждаме, че взимаме само подмножество свойства за този пример. Модернизацията няма да се оплаква от липсващи свойства - тъй като картографира само това, от което се нуждаем , дори няма да се оплаче, ако трябва да добавим свойства, които не са в JSON.

Сега можем да преминем към моделирането на интерфейса и да обясним някои от поясненията за модернизация:

public interface UserService { @GET("/users") public Call
    
      getUsers( @Query("per_page") int per_page, @Query("page") int page); @GET("/users/{username}") public Call getUser(@Path("username") String username); }
    

Метаданните, предоставени с пояснения, са достатъчни, за да може инструментът да генерира работещи внедрения.

В @GET анотацията казва на клиента, който HTTP метод за използване и на която ресурс, така например, чрез предоставяне на база URL на "//api.github.com" той ще изпрати искане до "//api.github.com / потребители “.

Водещото „/“ на относителния ни URL адрес казва на Retrofit, че това е абсолютен път към хоста.

Друго нещо, което трябва да се отбележи, е, че използваме напълно незадължителни параметри @Query , които могат да бъдат предадени като null, ако нямаме нужда от тях, инструментът ще се погрижи да игнорира тези параметри, ако нямат стойности.

И не на последно място, @Path позволява да посочим параметър на пътя, който ще бъде поставен вместо маркировката, която използвахме в пътя.

4. Синхронен / Асинхронен API

За да изградим повикване за HTTP заявка, първо трябва да изградим нашия обект за модернизация:

OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); Retrofit retrofit = new Retrofit.Builder() .baseUrl("//api.github.com/") .addConverterFactory(GsonConverterFactory.create()) .client(httpClient.build()) .build();

Модернизацията осигурява удобен конструктор за конструиране на необходимия ни обект. Той се нуждае от основния URL адрес, който ще се използва за всяко повикване на услуга, и фабрика за конвертори - която се грижи за синтактичния анализ на данните, които изпращаме, както и отговорите, които получаваме.

В този пример ще използваме GsonConverterFactory , който ще съпостави нашите JSON данни с потребителския клас, който дефинирахме по-рано.

Важно е да се отбележи, че различните фабрики служат за различни цели, така че имайте предвид, че можем също да използваме фабрики за XML, прото-буфери или дори да създадем такава за персонализиран протокол. За списък на вече внедрени фабрики можем да разгледаме тук.

Последната зависимост е OKHttpClient - която е HTTP & HTTP / 2 клиент за приложения за Android и Java. Това ще се погрижи за свързване със сървъра и изпращане и извличане на информация. Бихме могли да добавим и заглавки и прехващачи за всяко обаждане, което ще видим в нашата секция за удостоверяване.

Сега, когато имаме нашия обект за модернизация, можем да изградим нашето извикване на услуга, нека да разгледаме как да направим това по синхронен начин:

UserService service = retrofit.create(UserService.class); Call callSync = service.getUser("eugenp"); try { Response response = callSync.execute(); User user = response.body(); } catch (Exception ex) { ... }

Тук можем да видим как Retrofit се грижи за изграждането на нашия сервизен интерфейс, като инжектира кода, необходим за отправяне на заявката, въз основа на предишните ни анотации.

След това получаваме обект Call, който се използва за изпълнение на заявката към API на GitHub. Най-важният метод тук е изпълнение , което се използва за синхронно изпълнение на повикване и ще блокира текущата нишка, докато прехвърля данните.

След като повикването бъде изпълнено успешно, можем да извлечем тялото на отговора - вече върху потребителски обект - благодарение на нашия GsonConverterFactory .

Извършването на синхронно повикване е много лесно, но обикновено използваме неблокираща асинхронна заявка:

UserService service = retrofit.create(UserService.class); Call callAsync = service.getUser("eugenp"); callAsync.enqueue(new Callback() { @Override public void onResponse(Call call, Response response) { User user = response.body(); } @Override public void onFailure(Call call, Throwable throwable) { System.out.println(throwable); } });

Сега вместо метод за изпълнение, ние използваме метода на опашката - който приема интерфейс за обратно извикване като параметър за справяне с успеха или неуспеха на заявката. Имайте предвид, че това ще се изпълни в отделна нишка.

След като разговорът приключи успешно, можем да извлечем тялото по същия начин, както преди.

5. Създаване на клас за многократна употреба на ServiceGenerator

Сега, когато видяхме как да конструираме нашия обект за модернизация и как да консумираме API, можем да видим, че не искаме да продължаваме да пишем компилатора отново и отново.

Това, което искаме, е клас за многократна употреба, който ни позволява да създадем този обект веднъж и да го използваме повторно за целия живот на нашето приложение:

public class GitHubServiceGenerator { private static final String BASE_URL = "//api.github.com/"; private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()); private static Retrofit retrofit = builder.build(); private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); public static  S createService(Class serviceClass) { return retrofit.create(serviceClass); } }

All the logic of creating the Retrofit object is now moved to this GitHubServiceGenerator class, this makes it a sustainable client class which stops the code from repeating.

Here's a simple example of how to use it :

UserService service = GitHubServiceGenerator.createService(UserService.class);

Now if we, for example, were to create a RepositoryService, we could reuse this class and simplify the creation.

In the next section, we're going to extend it and add authentication capabilities.

6. Authentication

Most APIs have some authentication to secure access to it.

Taking into account our previous generator class, we're going to add a create service method, that takes a JWT token with the Authorization header :

public static  S createService(Class serviceClass, final String token ) { if ( token != null ) { httpClient.interceptors().clear(); httpClient.addInterceptor( chain -> { Request original = chain.request(); Request request = original.newBuilder() .header("Authorization", token) .build(); return chain.proceed(request); }); builder.client(httpClient.build()); retrofit = builder.build(); } return retrofit.create(serviceClass); }

To add a header to our request, we need to use the interceptor capabilities of OkHttp; we do this by using our previously define builder and by reconstructing the Retrofit object.

Note that this a simple auth example, but with the use of interceptors we can use any authentication such as OAuth, user/password, etc.

7. Logging

In this section, we're going to further extend our GitHubServiceGenerator for logging capabilities, which are very important for debugging purposes in every project.

We're going to use our previous knowledge of interceptors, but we need an additional dependency, which is the HttpLoggingInterceptor from OkHttp, let us add it to our pom.xml:

 com.squareup.okhttp3 logging-interceptor 3.9.0 

Сега нека разширим нашия клас GitHubServiceGenerator :

public class GitHubServiceGenerator { private static final String BASE_URL = "//api.github.com/"; private static Retrofit.Builder builder = new Retrofit.Builder() .baseUrl(BASE_URL) .addConverterFactory(GsonConverterFactory.create()); private static Retrofit retrofit = builder.build(); private static OkHttpClient.Builder httpClient = new OkHttpClient.Builder(); private static HttpLoggingInterceptor logging = new HttpLoggingInterceptor() .setLevel(HttpLoggingInterceptor.Level.BASIC); public static  S createService(Class serviceClass) { if (!httpClient.interceptors().contains(logging)) { httpClient.addInterceptor(logging); builder.client(httpClient.build()); retrofit = builder.build(); } return retrofit.create(serviceClass); } public static  S createService(Class serviceClass, final String token) { if (token != null) { httpClient.interceptors().clear(); httpClient.addInterceptor( chain -> { Request original = chain.request(); Request.Builder builder1 = original.newBuilder() .header("Authorization", token); Request request = builder1.build(); return chain.proceed(request); }); builder.client(httpClient.build()); retrofit = builder.build(); } return retrofit.create(serviceClass); } }

Това е последната форма на нашия клас, можем да видим как добавихме HttpLoggingInterceptor и го зададохме за основно регистриране, което ще регистрира времето, необходимо за извършване на заявката, крайната точка, състоянието на всяка заявка и т.н.

Важно е да разгледаме как проверяваме дали прехващачът съществува, за да не го добавим случайно два пъти.

8. Заключение

В това обширно ръководство разгледахме отличната библиотека за модернизация, като се фокусирахме върху нейния API за синхронизация / асинхронизация, някои най-добри практики за моделиране, удостоверяване и регистриране.

Библиотеката може да се използва по много сложни и полезни начини; за случай на напреднала употреба с RxJava, моля, разгледайте този урок.

И както винаги, изходният код може да бъде намерен в GitHub.