Einführung in die Nachrüstung

1. Übersicht

Retrofit ist ein typsicherer HTTP-Client für Android und Java - entwickelt von Square (Dagger, Okhttp).

In diesem Artikel erklären wir Ihnen, wie Sie Retrofit verwenden, wobei wir uns auf die interessantesten Funktionen konzentrieren. Insbesondere werden wir die synchrone und asynchrone API, ihre Verwendung bei der Authentifizierung, Protokollierung und einige gute Modellierungsmethoden erläutern.

2. Einrichten des Beispiels

Wir beginnen mit dem Hinzufügen der Retrofit-Bibliothek und des Gson-Konverters:

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

Die neuesten Versionen finden Sie unter Nachrüstung und Konverter-Gson im Maven Central-Repository.

3. API-Modellierung

Retrofit modelliert REST-Endpunkte als Java-Schnittstellen, wodurch sie sehr einfach zu verstehen und zu verwenden sind.

Wir werden die Benutzer-API von GitHub modellieren. Dies hat einen GET- Endpunkt, der dies im JSON-Format zurückgibt:

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

Beim Nachrüsten wird über eine Basis-URL modelliert und die Entitäten werden vom Schnittstellen vom REST-Endpunkt zurückgegeben.

Der Einfachheit halber werden wir einen kleinen Teil des JSON übernehmen, indem wir unsere Benutzerklasse modellieren , die die Werte annimmt, wenn wir sie erhalten haben:

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

Wir können sehen, dass wir für dieses Beispiel nur eine Teilmenge von Eigenschaften verwenden. Retrofit wird sich nicht über fehlende Eigenschaften beschweren - da es nur das abbildet, was wir benötigen , wird es sich nicht einmal beschweren, wenn wir Eigenschaften hinzufügen, die nicht im JSON enthalten sind.

Jetzt können wir zur Schnittstellenmodellierung übergehen und einige der Retrofit-Annotationen erläutern:

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); }
    

Die mit Anmerkungen versehenen Metadaten reichen aus, damit das Tool funktionierende Implementierungen generiert.

Die Annotation @GET teilt dem Client mit, welche HTTP-Methode und auf welcher Ressource verwendet werden soll. Wenn Sie beispielsweise eine Basis-URL von "//api.github.com" angeben, wird die Anforderung an "//api.github.com" gesendet / Benutzer ”.

Das führende "/" in unserer relativen URL teilt Retrofit mit, dass es sich um einen absoluten Pfad auf dem Host handelt.

Beachten Sie außerdem, dass wir vollständig optionale @Query- Parameter verwenden, die als Null übergeben werden können, wenn wir sie nicht benötigen. Das Tool ignoriert diese Parameter, wenn sie keine Werte haben.

Und zu guter Letzt können Sie mit @Path einen Pfadparameter angeben, der anstelle des im Pfad verwendeten Markups platziert wird.

4. Synchrone / asynchrone API

Um einen HTTP-Anforderungsaufruf zu erstellen, müssen wir zuerst unser Retrofit-Objekt erstellen:

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

Retrofit bietet einen praktischen Builder für die Erstellung unseres erforderlichen Objekts. Es benötigt die Basis-URL, die für jeden Serviceabruf verwendet wird, und eine Konverterfabrik, die sich um das Parsen der von uns gesendeten Daten und der erhaltenen Antworten kümmert.

In diesem Beispiel verwenden wir die GsonConverterFactory , die unsere JSON-Daten der zuvor definierten Benutzerklasse zuordnet .

Es ist wichtig zu beachten, dass verschiedene Fabriken unterschiedlichen Zwecken dienen. Denken Sie also daran, dass wir Fabriken auch für XML, Protopuffer oder sogar für ein benutzerdefiniertes Protokoll erstellen können. Eine Liste der bereits implementierten Fabriken finden Sie hier.

Die letzte Abhängigkeit ist OKHttpClient - ein HTTP- und HTTP / 2-Client für Android- und Java-Anwendungen. Dadurch wird die Verbindung zum Server hergestellt und Informationen gesendet und abgerufen. Wir könnten auch Header und Interceptors für jeden Anruf hinzufügen, die wir in unserem Abschnitt zur Authentifizierung sehen werden.

Nachdem wir unser Retrofit-Objekt haben, können wir unseren Serviceabruf erstellen. Schauen wir uns an, wie dies synchron durchgeführt wird:

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

Hier können wir sehen, wie Retrofit sich um den Aufbau unserer Serviceschnittstelle kümmert, indem wir den Code einfügen, der für die Anforderung erforderlich ist, basierend auf unseren vorherigen Anmerkungen.

Danach erhalten wir ein Call- Objekt, das zum Ausführen der Anforderung an die GitHub-API verwendet wird. Die wichtigste Methode ist hier execute , mit der ein Aufruf synchron ausgeführt wird und der aktuelle Thread beim Übertragen der Daten blockiert wird.

Nachdem der Aufruf erfolgreich ausgeführt wurde, können wir dank unserer GsonConverterFactory den Text der Antwort abrufen, der sich bereits auf einem Benutzerobjekt befindet .

Ein synchroner Anruf ist sehr einfach, aber normalerweise verwenden wir eine nicht blockierende asynchrone Anforderung:

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); } });

Anstelle der Methode execute verwenden wir jetzt die Methode enqueue , die eine Callback- Schnittstelle als Parameter verwendet, um den Erfolg oder Misserfolg der Anforderung zu behandeln. Beachten Sie, dass dies in einem separaten Thread ausgeführt wird.

Nachdem der Anruf erfolgreich beendet wurde, können wir den Körper auf die gleiche Weise wie zuvor abrufen.

5. Erstellen einer wiederverwendbaren ServiceGenerator- Klasse

Nachdem wir nun gesehen haben, wie unser Retrofit-Objekt erstellt und eine API verwendet wird, können wir sehen, dass wir den Builder nicht immer wieder schreiben möchten.

Was wir wollen, ist eine wiederverwendbare Klasse, mit der wir dieses Objekt einmal erstellen und für die Lebensdauer unserer Anwendung wiederverwenden können:

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 

Erweitern wir nun unsere GitHubServiceGenerator- Klasse:

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); } }

Dies ist die endgültige Form unserer Klasse. Wir können sehen, wie wir den HttpLoggingInterceptor hinzugefügt haben , und wir haben ihn für die Basisprotokollierung festgelegt. Dabei wird die Zeit protokolliert, die für die Anforderung benötigt wurde, der Endpunkt, der Status für jede Anforderung usw.

Es ist wichtig zu sehen, wie wir prüfen, ob der Interceptor vorhanden ist, damit wir ihn nicht versehentlich zweimal hinzufügen.

8. Fazit

In diesem ausführlichen Handbuch haben wir uns die hervorragende Retrofit-Bibliothek angesehen, indem wir uns auf die Sync / Async-API konzentriert haben, einige bewährte Methoden für Modellierung, Authentifizierung und Protokollierung.

Die Bibliothek kann auf sehr komplexe und nützliche Weise verwendet werden. Für einen erweiterten Anwendungsfall mit RxJava schauen Sie sich bitte dieses Tutorial an.

Und wie immer ist der Quellcode auf GitHub zu finden.