Retrofit 2

Bezpłatny fragment - Retrofit 2

Sieciowe aplikacje dla Androida i Javy


Informatyka stosowana
Polski
Objętość:
139 str.
ISBN:
978-83-8245-694-3

Rozdział I. Informacje ogólne

1. Czym jest Retrofit 2?

Retrofit 2 jest klientem HTTP przeznaczonym dla platformy Android i Java (także Kotlin) stworzonym przez firmę Square. Biblioteka zapewnia mechanizm uwierzytelniania i interakcji z sieciowym API oraz wysyłania żądań sieciowych za pomocą innej biblioteki o nazwie OkHttp. Retrofit 2 sprawia, że pobieranie danych w formacie JSON lub XML za pomocą sieciowego API jest dość proste. Po pobraniu danych są one mapowane do postaci obiektu Java (POJO), który należy zdefiniować dla każdego zasobu.

2. Jak działa Retrofit 2?

Retrofit modeluje punkty końcowe (end-points) REST do postaci klas Javy, dzięki czemu są one łatwiejsze do zrozumienia i wykorzystania. Na przykład zakładając, że istnieje serwer oferujący obiekty JSON w następującym formacie:

{

id:1,

name:”Anna”

surname:”Doe”

}

a w kodzie klienta będziemy posługiwali się zmapowaną klasą:

public class Mother{

@JsonProperty(„id”) private int id;

@JsonProperty(„name ”) private String name;

@JsonProperty(„surname ”) private String surname;


@JsonProperty(„id”)

public int getId(){return id};

@JsonProperty(„name ”)

public String getName(){return name};

@JsonProperty(„surname ”)

public String getSurname (){return surname};

@JsonProperty(„id”)

public void setId(String name){this.id = id;}

@JsonProperty(„name”)

public void setName(String name){this.name = name;}

@JsonProperty(„surname ”) public void setSurname(String surname)

{this.surname = surname;}

}

i interfejsem reprezentującym usługę zarządzającą naszą klasą:

public interface MotherService{


@GET(”/members”)

public Call<List<Mother>> getMembers(

@Query(„per_page”) int per_page,

@Query(„page”) int page);


@GET(”/member/{name}”)

public Call<Mother> getMother(@Path(„name”) String name);

}

w kilku krokach można uzyskać dostęp do danych z serwera za pomocą prostego wywołania metody:

RetroAPI retroAPI =

retrofit.create(RetroAPI.class);

Call<User> call = retroAPI.getUser(„1”);

call. enqueue(this);

3. Jakie znaczenie ma biblioteka OkHttp?

OkHttp jest niezależną biblioteką wspomagającą Retrofit 2. OkHttp to wydajny klient obsługujący standard HTTP/2, pule połączeń, kompresję Gzip i buforowanie odpowiedzi. Użycie OkHttp jest bardzo proste:

OkHttpClient client = new OkHttpClient();


String run(String url) throws IOException {

Request request = new Request. Builder()

.url(url)

.build();


try (Response response =

client.newCall(request).execute()){

return response.body().string();

}

}

4. Czym jest JSON?

JSON (JavaScript Object Notation) to lekki format wymiany danych. Łatwy dla ludzi do czytania i pisania, a także łatwy dla komputerów do analizowania i generowania. Jest on oparty na podzbiorze standardu języka programowania JavaScript ECMA-262. JSON to format tekstowy, który jest całkowicie niezależny od jakiegokolwiek docelowego języka, który będzie go przetwarzał, ale wykorzystuje konwencje znane programistom języków z rodziny C, w tym C, C ++, C #, Java, JavaScript, Perl, Python i wiele innych. JSON jest dobrym i popularnym językiem wymiany danych. Dostęp do nich w formacie JSON jest bardziej naturalne z poziomu języka JavaScript niż dostęp do tych samych danych w formacie XML, ponieważ JSON stanowi składniowy podzbiór języka JavaScript. Wbrew podobieństwu w nazwie, nie jest już jednak tak naturalny dla Javy i wymaga stosowania specjalnych bibliotek. JSON jest alternatywą i poważną konkurencją dla formatu XML.


Działanie i budowa JSON jest oparta o dwie struktury: pary klucz=wartość oraz uporządkowane listy wartości:

„mother”: {

„id”: „12”,

„name”: „Anna”,

„items”: {

„shoes”: [

{„color”: „red”, „type”: „boots”},

{„ color ": „green”, " type ": „flipflops”}

]

}

}

}

5. Czym jest REST?

REST to skrót od Representational state transfer (zmiana stanu poprzez reprezentacje). REST jest stylem architektury oprogramowania wywiedzionym z doświadczeń przy pisaniu specyfikacji protokołu HTTP dla systemów rozproszonych. Jest powszechnie używany do tworzenia interaktywnych aplikacji korzystających z usług sieciowych. Usługa sieciowa, która jest zgodna z tymi wytycznymi, nosi nazwę RESTful. Taka usługa musi udostępniać swoje zasoby sieciowe w postaci tekstowej i umożliwiać ich odczyt i modyfikację za pomocą protokołu bezstanowego i wstępnie zdefiniowanego zestawu operacji. Takie podejście umożliwia współdziałanie między systemami komputerowymi, które świadczą te usługi. REST jest alternatywą dla innego mechanizmu przesyłania danych o nazwie SOAP jako sposób dostępu do usługi sieciowych.

6. Z czego składa się adres usługi REST?

Adres usługi REST może wyglądać następująco:

http://www.domain.com/members?name=A&page=5

Składa się on z trzech elementów: adresu bazowego (base url, server url), adresu końcowego (endpoint) oraz parametrów zapytania (query parameters).

Adresem bazowym jest adres serwera dostarczającego API dla usług REST. W powyższym przykładzie to „http://www.domain.com/”. Adresami końcowymi są adresy poszczególnych usług. Tutaj to „members”. Kwestią umowną jest czy adres bazowy powinien kończyć się ukośnikiem, a adresy końcowe być go pozbawione czy raczej adresy powinny się zaczynać ukośnikami. W Retrofit 2 standardem jest umieszczanie ukośnika na końcu klasy bazowej. Adres usługi REST mogą kończyć parametry zapytania, które uszczegóławiają adres końcowy.

7. Jak działa architektura REST?

REST API umożliwia tworzenie aplikacji internetowych posługujących się operacjami określanymi skrótem CRUD (create, retrieve, update, delete). REST w pracy posługuje się określonymi metodami protokołu HTTP korzystając z nich na podstawie z góry przyjętej konwencji i używając formatu URI (Uniform Resource Identifier) dla wykonania określonych działań na zasobach sieciowych:


— GET — dla odczytywania, zaznaczania, pobierania zasobu.

— POST — dla tworzenia i umieszczania zasobów.

— PUT — dla aktualizacji i modyfikacji zasobów.

— DELETE — dla usunięcia i skasowania zasobu.

— PATCH — dla aktualizacji i modyfikacji zasobów

8. Jak działa zapytanie metodą HTTP GET?

Zapytanie GET służy do pobierania informacji o zasobach bez ich modyfikacji. GET nie zmienia stanu rzeczy i dlatego metoda uznawana jest za bezpieczną. Wykonywanie wielu identycznych żądań powinno dawać ten sam wynik za każdym razem, dopóki inny interfejs API (POST lub PUT) nie zmieni stanu zasobu na serwerze. Przykłady zapytań:


— HTTP GET http://www.domain.com/members

— HTTP GET http://www.domain.com/members?name=A&page=5

— HTTP GET http://www.domain.com/members/123

— HTTP GET http://www.domain.com/members/123/name

9. Jak działa metoda HTTP POST?

Metoda POST służy do tworzenia nowego zasobu w kolekcji zasobów. Nie jest to metoda bezpieczna, bowiem nie gwarantuje, że wywołanie dwóch identycznych żądań POST spowoduje powstanie dwóch zasobów zawierających te same informacje (z wyjątkiem identyfikatorów zasobów). Przykłady zapytań metodą POST:


— HTTP POST http://www.domain.com/members

— HTTP POST http://www.domain.com/members/123/items

10. Jak działa metoda PUT?

Metoda PUT służy głównie do aktualizowania istniejącego zasobu. Jeśli zasób nie istnieje, można zdecydować o utworzeniu nowego zasobu. Jeśli nowy zasób został utworzony przez metodę PUT, serwer pochodzenia powinien poinformować użytkownika za pośrednictwem odpowiedzi kodu HTTP 201 (CREATED), a jeśli istniejący zasób zostanie zmodyfikowany za pomocą kodu 200 (OK) lub 204 (NO CONTENT). Przykłady wykorzystania metody PUT:


— HTTP PUT http://www.domain.com/members/123

— HTTP PUT http://www.domain.com/members/123/items/456

11. Na czym polega działanie metody DELETE?

Metoda DELETE służy do usuwania zasobów oznaczonych przez identyfikator żądania URI. Wielokrotne wywoływanie metody DELETE na tym samym zasobie nie zmienia wyniku, ale zwróci błąd kod HTTP 404 (NOT FOUND), ponieważ został on już usunięty. Przykłady wykorzystania tej metody:


— HTTP DELETE http://www.domain.com/member/123

— HTTP DELETE http://www.domain.com/member/123/item/456

12. Jakie jest zadanie metody PATCH?

Żądania wykonane za pomocą metody PATCH ma na celu częściową aktualizację zasobu. Metoda PATCH jest właściwym wyborem do częściowej aktualizacji istniejącego zasobu, a PUT powinna być używana tylko wtedy, gdy zastępuje się zasób w całości. Pomyślna odpowiedź na żądania PATCH powinna realizować się kodem odpowiedzi 200 (OK) lub 204 (NO CONTENT). Kod 404 (NOT FOUND) powinien być zwrócony gdy identyfikator jest wadliwy lub nie został znaleziony.

13. Jakie są zalety architektury REST?

Korzystanie z architektury REST do budowy usług sieciowych ma wiele zalet. Należą do nich:

— Lekki charakter wzorca architektonicznego REST, co jest dobre przy ograniczonej przepustowości przesyłu danych.

— Łatwość i szybkość tworzenia.

— Popularność tego wzorca wśród serwisów takich jak Twitter.

— Dominowanie w aplikacjach mobilnych ze względu na szybkość i wydajność.

14. Jakie adnotacje wykorzystuje architektura REST?

Anotacjami mogą zostać oznaczone klasy, metody, zmienne, parametry czy też moduły. Tak jak tagi w dokumentacji Javy, anotacje mogą być odczytywane z plików źródłowych lub plików o rozszerzeniu. class generowanych przez kompilator. Pozwalają one na rozszerzenie funkcjonalności klas i obiektów. Najczęściej wykorzystywane anotacje po stronie serwera podczas tworzenia usług sieciowych REST to:


— @Path (javax.ws.rs.Path) — służy do określenia identyfikatora URI, za pośrednictwem którego można uzyskać dostęp do zasobu i interfejsu API.

— @GET (javax.ws.rs.GET) — metoda Javy oznaczona tą anotacją obsługuje żądania GET.

— @POST (javax.ws.rs.POST) — metoda Javy oznaczona tą anotacją obsługuje żądania POST.

— @PUT (javax.ws.rs.PUT) — metoda Javy oznaczona tą anotacją obsługuje żądania PUT.

— @DELETE (javax.ws.rs.DELETE) — metoda Javy oznaczona tą anotacją obsługuje żądania DELETE.

— @PathParam (javax.ws.rs.PathParam) — typ parametru, który można wyodrębnić do użycia w klasie zasobów. Parametry ścieżki URI są wyodrębniane z identyfikatora URI żądania, a nazwy parametrów odpowiadają nazwom zmiennych szablonu ścieżki URI określonych w adnotacji na poziomie klasy @Path.

— @QueryParam (javax.ws.rs.QueryParam) — typ parametru, który można wyodrębnić do użycia w klasie zasobów. Parametry zapytania są wyodrębniane z parametrów zapytania URI żądania.

— @CookieParam — parametr wyodrębniający informacje z plików cookie zadeklarowanych w nagłówkach HTTP związanych z plikami cookie.

— @MatrixParam (javax.ws.rs.MatrixParam) — parametr wyodrębniający informacje z segmentów ścieżki URL.

— @FormParam (javax.ws.rs.FormParam) — parametr przetwarzający dane formularza.

— @HeaderParam (javax.ws.rs.HeaderParam) — parametr wyodrębniający informacje z nagłówków

— @Context (javax.ws.rs.core.Context) — wielofunkcyjna anotacja, której celem jest dostarczenie różnego rodzaju obiektów.

— @Consumes (javax.ws.rs.Consumes) — wskazuje na tym MIME, który metoda może przetworzyć.

— @Produces (javax.ws.rs.Produces) — wskazuje na tym MIME, który metoda może zwrócić.


Retrofit zarządzą przetwarzaniem informacji z serwera konsumując je za pomocą zestawu własnych anotacji. Poniżej kilka z podstawowych:


— @Path (retrofit2.http.Path) — anotacja służy do podmieniania parametru w ścieżce URL.

— @GET (retrofit2.http.GET) — metoda oznaczona tą anotacją zarządza zapytaniem GET.

— @POST (retrofit2.http.POST) — metoda oznaczona tą anotacją zarządza zapytaniem POST.

— @PUT (retrofit2.http. PUT) — metoda oznaczona tą anotacją zarządza zapytaniem PUT.

— @PATCH (retrofit2.http.PATCH) — metoda oznaczona tą anotacją zarządza zapytaniem PATCH.

— @HEAD (retrofit2.http. HEAD) — metoda oznaczona tą anotacją zarządza zapytaniem HEAD.

— @Query (retrofit2.http. Query) — anotacja dodaje parametr do ścieżki URL.

— @Multipart (retrofit2.http. Multipart) — anotacja przeznaczona do oznaczenia odpowiedzi jako typu Multipart.

15.Jaka jest różnica między Retrofit 1 a Retrofit 2?

Biblioteka Retrofit2 stanowi ewolucyjne rozwinięcie Retrofit 1. Nie wprowadzono w niej żadnych nowych mechanizmów oprócz drobnych zmian. Przede wszystkim Retrofit2 jest od razu zintegrowany z biblioteką OkHttp. Ponadto zapewniono obsługę większej ilości konwerterów, które muszą być dostarczone w osobnych bibliotekach, uproszczono proces tworzenia obiektu Retrofit. Największa zmiana to konwencja umieszczania ukośnika na końcu adresu bazowego i jego unikanie na początku adresu końcowego oraz interfejs Call, który obsługuje wywołania symetryczne i asymetryczne.

16. Na jakiej licencji działa Retrofit 2?

Retrofit 2 działa na licencji Apache License w wersji 2.0. W dużym skrócie pozwala na używanie, modyfikowanie i redystrybucję programu w postaci źródłowej, lub binarnej, bez obowiązku udostępnienia kodu źródłowego. Oznacza to, że kod na tej licencji można włączyć do zamkniętych programów, pod warunkiem zachowania zgodności z warunkami tej licencji.

17. Gdzie można znaleźć kod źródłowy Retrofit 2?

Retrofit 2 posiada ogólnie dostępny kod na Githubie pod adresem:

https://github.com/square/retrofit

18. Gdzie można znaleźć dokumentację Retrofit 2?

Pełna dokumentacja dla wersji 2.x znajduje się tutaj:

https://square.github.io/retrofit/2.x/retrofit/

Rozdział II. Instalacja

1. Jakie biblioteki są wymagane do pracy z Retrofit 2?

W celu utworzenia projektu dla Retrofit można posłużyć się środowiskiem Eclipse i Gradle. Należy założyć, że są one poprawnie zainstalowane i skonfigurowane. Zamiast Eclipsa można bez większych problemów wykorzystać środowisko IntelliJ. W Eclipsie utworzymy nowy projekt Java o nazwie RetrofitProj:

File -> New -> Gradle -> Gradle Project

Wybieramy opcję Gradle Wrapper. W utworzonym katalogu o nazwie RetrofitProj znajduje się plik o nazwie „build.gradle”. Należy edytować go w sekcji:

dependencies {}

dodając następujące wpisy:

implementation 'com.squareup.retrofit2:retrofit:2.9.0”

implementation 'com.squareup.retrofit2:converter-gson:2.9.0”

Pierwszy wpis to sama biblioteka. Drugi to wybrany konwerter dla obsługi formatu JSON. W momencie pisania tej książki najnowszą wersją była ta oznaczona numerem 2.9.0. Aby sprawdzić jaka jest najnowsza wersją w momencie jej czytania można wejść na stronę:

https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit

Pomocniczo Retrofit 2 często jest wspomagany przez biblioteki Jackson i RxJava, ale nie jest to konieczne:

compile group: 'com.fasterxml.jackson.core”, name: „jackson-annotations”, version: „2.12.1”

compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0”

Ponadto Retrofit 2 wymaga minimum Javy w wersji 8+, a dla Android poziomu API 21+.


Teraz możemy pobrać biblioteki klikając w Eclipsie na nazwę projektu prawym przyciskiem myszy i wybierając:

Gradle->Refresh Gradle Projekt.

Po tych krokach Retrofit 2 jest gotowy do pracy.

2. Jak testować Retrofit 2?

Aby testować działanie z Retrofit 2 należy dysponować środowiskiem, które jest zdolne zapewniać usługi sieciowe obsługujące schemat REST. Może to być serwer lokalny lub zdalny. Szybkim i łatwym rozwiązaniem jest skorzystanie z darmowego serwisu znajdującego się pod adrsem:

https://mockapi.io.

Dzięki niemu otrzymamy dostęp do testowego serwera i prostych obiektów oferowanych za pomocą REST w formacie JSON. Po utworzeniu konta zostaniemy przeniesieni do panelu gdzie będziemy mogli zdefiniować naszą strukturę obiektów. Na samej górze zobaczymy adres nasze usługi, który wygląda mniej więcej tak:

https://XXXYYYZZZ.mockapi.io/:endpoint

Teraz klikając na przycisk „New Resorce” możemy utworzyć nowe zasoby. Do testów wystarczy jeden o nazwie User. Przesuwając pasek na nazwie zbioru możemy regulować ilość obiektów w zbiorze. Zbiór powinien zawiera przynajmniej kilkadziesiąt obiektów. Jeżeli najedziemy kursorem na nazwę zbioru możemy kliknąć na przycisk Edit i zmienić strukturę obiektu. Obiekty są generowane automatycznie, ale można je zmienić klikając na przycisk Data. Obiekt User będzie zawierać następujące pola: id, createdAt, name, awatar. Kilka przykładowych obiektów ze zbioru wygląda tak:

[

{

„id”: „1”,

„createdAt”: „2021-02-06T05:03:06.694Z”,

„name”: „Julius Zemlak”,

„avatar”: "https://s3.amazonaws.com/uifaces/faces/twitter/richardgarretts/128.jpg"

},

{

„id”: „2”,

„createdAt”: „2021-02-06T06:53:32.841Z”,

„name”: „Brown Wilkinson”,

„avatar”: "https://s3.amazonaws.com/uifaces/faces/twitter/michaelcomiskey/128.jpg"

},

]

Oprócz danych zostaną też udostępniony metody REST API dla zarządzania zbiorem w następującym zakresie:

Biorąc pod uwagę wcześniej wygenerowany link do usługi, adres, dzięki któremu będziemy mogli pobrać jeden obiekt o identyfikatorze id=1 to:

https://XXXYYYZZZ.mockapi.io/user/1

Powyższy link pozwala otrzymać następujące dane:

{

„id”: „1”,

„createdAt”: „2021-02-06T05:03:06.694Z”,

„name”: „Julius Zemlak”,

„avatar”:

“https://s3.amazonaws.com/uifaces/faces/twitter/richardgarretts/128.jpg”

}

3. W jaki sposób utworzyć klasy odpowiadające obiektom JSON?

Jak można było zauważyć w poprzednim przykładzie ideą stojącą za biblioteką Retrofit 2 jest mapowanie obiektów JSON na klasy Java typu POJO. Te klasy należy utworzyć samodzielnie. Można oczywiście zrobić to ręcznie. Zatem z obiektu JSON, który jest dostępny za pomocą linku:

https://XXXYYYZZZ.mockapi.io/user/1

trzeba ręcznie utworzyć klasę User. Nie stanowi to większego problemu przy kilku polach. Gdy jest ich kilkanaście lub więcej tworzenie pól oraz metod typu getter i setter jest dość uciążliwe. Żeby ułatwić naszą pracę możemy skorzystać z darmowych usług internetowych, które generują nam klasę typu POJO. Jedna z takich usług znajduję się pod następującym adresem:

http://www.jsonschema2pojo.org

Na pierwszej stronie, w głównym oknie należy wkleić następujący obiekt JSON:


{

„id”: „1”,

„createdAt”: „2021-02-06T05:03:06.694Z”,

„name”: „Julius Zemlak”,

„avatar”: "https://s3.amazonaws.com/uifaces/faces/twitter/richardgarretts/128.jpg"

}


i ustawić następujące opcje:

Package: com.myretrofitproj.user

Class name: User

Target language: Java.

Source type:: JSON

Annotation style:: Gson

Include getters and setters: Yes

Po naciśnięciu przycisku „Preview” otrzymamy wygenerowaną klasę:

package com.myretrofitproj.user;


import com.google.gson.annotations. Expose;

import com.google.gson.annotations.SerializedName;


public class User {

@SerializedName(„id”)

@Expose

private String id;

@SerializedName(„createdAt”)

@Expose

private String createdAt;

@SerializedName(„name”)

@Expose

private String name;

@SerializedName(„avatar”)

@Expose

private String avatar;


public String getId(){return id;}

public void setId(String id){this.id = id;}

public String getCreatedAt(){return createdAt;}

public void setCreatedAt(String createdAt){

this.createdAt = createdAt;}

public String getName(){return name;}

public void setName(String name){

this.name = name;}

public String getAvatar(){return avatar;}

public void setAvatar(String avatar){

this. avatar = avatar;}

}

Jak widać w prosty sposób można uzyskać gotową do pracy klasę typu POJO.

4. Jak przetestować prawidłową instalację biblioteki Retrofit 2?

W tym celu można posłużyć się prostym przykładem, dzięki któremu będziemy w stanie pobrać pojedynczy obiekt klasy User zależnie od wartości pola id. Zaczniemy od klasy zawierającej API dla naszej klasy:

import retrofit2.Call;

import retrofit2.http.GET;

import retrofit2.http.Path;

import retrofit2.http. Query;


public interface RetroAPI{

@GET(„users/{id}”)

public Call<User> getUser(@Path(„id”) String id);

}

Klasa zawiera jedną metodę przyjmująca za argument wartość id i zwracająca obiekt User. Metoda jest oznaczona adnotacją @GET z parametrem stanowiącym ścieżkę do usługi REST. Teraz pora na ogólną klasę zarządzającą połączeniem:

import com.google.gson.Gson;

import com.google.gson.GsonBuilder;

import retrofit2.Call;

import retrofit2.Callback;

import retrofit2.Response;

import retrofit2.Retrofit;

import retrofit2.converter.gson.

GsonConverterFactory;


public class UserGetController implements Callback<User> {

public void start(){}


@Override

public void onResponse(Call<User> call,

Response<User> response){}


@Override

public void onFailure(Call<User> call, Throwable t){t.printStackTrace();}

}

W tej klasie należy najpierw zadeklarować pole ze wskazaniem adresu bazowego naszej usługi:

static final String BASE_URL = "https://XXXYYYXXX.mockapi.io/";

W metodzie start() należy utworzyć obiekt Gson obsługujący konwersję formatu JSON. Następnie trzeba utworzyć obiekt Retrofit, który zarządza połączeniem. Z obiektu wywołujemy wcześniej zadeklarowaną klasę z API i przekazujemy go do kolejki aby otrzymać wynik czyli obiekt:

Gson gson = new GsonBuilder()

.setLenient()

.create();


Retrofit retrofit = new Retrofit. Builder()

.baseUrl(BASE_URL)

.addConverterFactory(GsonConverterFactory

.create(gson))

.build();


RetroAPI retroAPI = retrofit.create(RetroAPI.class);

Call<User> call = retroAPI.getUser(„1”);

call. enqueue(this);

W metodzie onResponse() oczekujemy na właściwy obiekt:

if(response.isSuccessful()){

User user = response.body();

System.out.println("Result="+user.getId());

}

else{System.out.println(response.errorBody());}

Teraz pora stworzyć klasę bazową dla wywołania:

public class TestRetrofit{

public static void main(String args[]){

TestGetController controller =

new TestGetController ();

controller.start();

}

}

W konsoli powinniśmy zobaczyć napis: Result=1.

5. Czym są konwertery?

Retrofit nie potrafi samodzielnie przetwarzać danych pobranych z serwera. W przeszłości Retrofit polegał jedynie na bibliotece Gson w celu serializacji i deserializacji danych w formacie JSON. Obecnie wspiera wiele różnych silników do parsowania danych. Jednak jeżeli nie celujemy w konkretne rozwiązania, Gson całkowicie wystarcza do pracy z Retrofit. Poniżej umieszczono listę dostępnych konwerterów:


— Gson.

— Jackson.

— Moshi.

— Protobuf.

— Wire.

— XML.

— JAXB.

— Scalars.


Jeżeli pojawi się potrzeba komunikacji z formacie nieznanym Retrofit 2 lub chcemy użyć innej biblioteki do konwersji, można utworzyć własny konwerter. Musi on dziedziczyć klasę Converter. Factory.

Rozdział III. Implementacja

1. Jakie są podstawowe anotacje w Retrofit 2?

Podstawowe anotacje potrzebne do pracy z Retrofit 2 to:


— @JsonProperty, @SerializedName — anotacje przeznaczone do zmiany nazwy pola w ramach serializacji. Bez nich nazwa jest taka sama jak nazwa zmiennej.

— @Path — służy do nadania nazwy parametrowi w metodzie, który potem zostanie użyty w ścieżce.

— @Query — służy do przekazania parametru do ścieżki.

— @Url — anotacja, której celem jest przekazanie ścieżki bez parametrów.

— @GET — metoda oznaczona tą anotacją obsługuje żądania GET. Dotyczy pobierania zarówno całej listy obiektów jak i pojedynczych egzemplarzy.

— @POST — anotacja przeznaczona do wysyłania danych za pomocą formularza.

— @PUT — metoda oznaczona tą anotacją ma na celu aktualizację pojedynczego obiektu.

— @DELETE — metoda oznaczona tą anotacją zajmuje się usuwaniem zasobów.

— @Body — adnotacja wskazująca obiekt, który ma być przesłany jako część formularza.

— @Header — dzięki ten anotacji można przekazywać nagłówki w formularzach.

2. Jakie są podstawowe kroki żeby zacząć prace z Retrofit 2?

Aby poprawnie zaimplementować Retrofit należy wykonać następujące kroki:


— Zidentyfikować adres usługi sieciowej.

— Zidentyfikować oferowane API usługi sieciowej.

— Utworzyć klasę odpowiadającą obiektowi usługi sieciowej.

— Utworzyć dowolny interfejs zawierający metody odpowiadające oferowanemu API (punkt b) i oznaczyć je anotacjami wskazującymi na metody HTTP. Parametrami w tych anotacjach mają być ścieżki URI konkretnych usług. Z kolei parametrami metod powinny być argumenty przekazywane do tych ścieżek.

— Utworzyć dla każdej usługi (punkt d) dowolną klasę implementującą interfejs Call z parametrem stanowiącym klasę obiektu usługi sieciowej (punkt c). Klasa powinna tworzyć obiekt klasy zawierającej metody serwisowej (punkt d) wobec adresu usługi (punkt a).

3. Jak przebiega podstawowy tok pracy z Retrofit 2?

Zgodnie z tym co powiedziano wcześniej zacząć należy od identyfikacji usługi sieciowej. Musimy określić adres oraz oferowane API. Posłużymy się testową usługa z poprzedniego rozdziału:

https://XXXYYYZZZ.mockapi.io/:endpoint

Oferuje ona kilka metod do manipulacji zasobem sieciowym:

Zatem jeżeli chcemy pobrać wszystkie obiekty ze zbioru musimy użyć metody GET korzystając z następującego adresu:

https://XXXYYYZZZ.mockapi.io/users

Nie ma potrzeby korzystania z całego API. Będziemy korzystać tylko z tych metod, które są nam potrzebne. Aby rozpocząć pracę z Retrofit 2 musimy mieć klasę odpowiadającą obiektowi JSON. W poprzednim rozdziale pokazano jak to zrobić pry użyciu darmowej usługi internetowej. Wystarczy pobrać jeden obiekt za pomocą linku:

https://XXXYYYZZZ.mockapi.io/users/1

następnie wkleić wynik w okienko generatora i pobrać wygenerowany kod klasy POJO. Kolejny krok to utworzenie interfejsu o dowolnej nazwie. Tutaj to będzie RetroAPI:

import retrofit2.Call;

import retrofit2.http.Body;

import retrofit2.http.DELETE;

import retrofit2.http.GET;

import retrofit2.http.PATCH;

import retrofit2.http.POST;

import retrofit2.http. PUT;

import retrofit2.http.Path;


public interface RetroAPI{


@GET(„users/{id}”)

public Call<User> getUser(@Path(„id”) String id);


@GET(„users/”)

public Call<List<User>> getUsers( );


@DELETE(„users/{id}”)

public Call<ResponseBody> deleteUser(@Path(„id”)

String id );


@POST(„users/”)

Call<ResponseBody> postUser(@Body User user);


@PATCH(„users/{id}”)

Call<ResponseBody> patchUser(@Path(„id”) String id,

@Body User user);

}

Następnie dla każdej z obsługiwanych metod należy utworzyć osobną klasę. Nie jest to konieczne i da się zaimplementować wszystkie metody w jednej klasie, ale tak lepiej zorganizować całość obsługi dostarczonego API. Nie będziemy pokazywać implementacji wszystkich metod. Skupimy się tylko na metodzie GET pobierającej jeden obiekt. Zaczniemy od obsłużenia metody pobierającej jeden obiekt według parametru o nazwie id. Utworzymy w tym celu klasę o nazwie UserGetController. Musi ona implementować interfejs Call, którego parametr musi być zgodny typem zwracanym przez metodę z interfejsu RetroAPI. Zatem metoda:

@GET(„users/{id}”)

public Call<User> getUser(@Path(„id”) String id);

wymaga następującej klasy:

public class UserGetController implements Callback<User>{…}

Klasa ta musi zaimplementować dwie obowiązkowe metody:

@Override

public void onResponse(Call<User> call, Response<User> response){}

@Override

public void onFailure(Call<User> call, Throwable t){}

Także tutaj typ parametrów musi być zgodny z typem zwracanym w interfejsie RetroAPI. Dodamy do tego własną metodę start(). Musi ona wykonywać cztery zadania:


— Utworzyć wybrany przez nas konwerter z formatu JSON do klasy Java.

— Utworzyć obiekt Retrofit, któremu należy przekazać adres bazowy oraz wybrany konwerter.

— Utworzyć obiekt stanowiący implementację interfejsu reprezentującego usługę sieciową.

— Wywołać metodę i przekazać jest klasę zwrotną celem otrzymania wyniku.

public void start(){

//1

Gson gson = new GsonBuilder()

.setLenient()

.create();

//2

Retrofit retrofit = new Retrofit. Builder()

.baseUrl(BASE_URL)

.addConverterFactory(GsonConverterFactory.create(gson))

.build();

//3

RetroAPI retroAPI =

retrofit.create(RetroAPI.class);

//4

Call<User> call = retroAPI.getUser(„1”);

call. enqueue(this);

}

W powyższym przykładnie BASE_URL oznacza adres bazowy naszej usługi:

https://XXXYYYZZZ.mockapi.io

Przekazanie argumentu do metody getUser() zachodzi w naszym przykładzie na sztywno i powinno być inaczej zrealizowane w praktyce. Wynik wywołania metody jest obsługiwany przez dwie metody:

@Override

public void onResponse(Call<User> call, Response<User> response){

if(response.isSuccessful()){

User user = response.body();

}

}


@Override

public void onFailure(Call<User> call, Throwable t){t.printStackTrace();}

4. Jakie znaczenie ma interfejs Call?

Implementacja tego interfejsu umożliwia wywoływanie metody Retrofit, która wysyła żądanie do serwera i zwraca odpowiedź. Każde wywołanie tworzy osobne żądanie i odpowiedź HTTP. Należy się posłużyć jej metodą o nazwie clone(), aby utworzyć wiele wywołań z tymi samymi parametrami do tego samego serwera celem implementacji poolingu lub ponowienia nieudanego połączenie.


Utworzenie implementacji interfejsu następuje przez wywołanie odpowiedniej metody odpowiadającej API usługi sieciowej. Abstrakcyjnym metodom interfejsu:

@GET(„users/{id}”)

public Call<User> getUser(@Path(„id”) String id );

@GET(„users/”)

public Call<List<User>> getUsers( );

@DELETE(„users/{id}”)

public Call<ResponseBody> deleteUser(@Path(„id”) String id );

@POST(„users/”)

Call<ResponseBody> postUser(@Body User user);

@PATCH(„users/{id}”)

Call<ResponseBody> patchUser(@Path(„id”) String id, @Body User user);

odpowiadają następujące wywołania:

Call<User> call = retroAPI.getUser(„1”);

Call<List<User>> call = retroAPI.getUsers();

Call<ResponseBody> call = retroAPI.deleteUser(„1”);

Call<ResponseBody> call = retroAPI.postUser( user);

Call<ResponseBody> call = retroAPI.patchUser(„1”, user);

5. W jaki sposób można wywołać połączenie za pomocą interfejsu Call?

Połączenie z serwerem może być wykonane synchronicznie lub asynchronicznie. Do tej pory widzieliśmy wyłącznie asynchroniczne, które można spotkać najczęściej. Wykonywane jest ono za pomocą metody o nazwie enqueue() przyjmującej jako argument obiekt implementujący interfejs Callback.

Call<User> call = retroAPI.getUser(„1”);

call. enqueue(this);

Typ parametru klasy Callback musi zgadzać się z typem interfejsu Call.

public class UserGetController implements Callback<User>{…}

Jak pokazano w dotychczasowych przykładach implementacja interfejsu Callback następowała w tej samej klasie. Wymusza to pojawienie się metod obsługujących wyniki połączenia. Za argument przyjmują one zgodny z typem interfejs Call:

public void onResponse(Call<User> call, Response<User> response){};

public void onFailure(Call<User> call, Throwable t){}

Alternatywą dla wywołania asynchronicznego jest wywołanie synchroniczne za pomocą metody o nazwie execute(). Zwraca ona od razu obiekt Response z typem zgodnym z wywołaniem:

Call<User> call = retroAPI.getUser(„1”);

Response<User> Response=call. execute();

W obu przypadkach połączenie można anulować w dowolnym momencie za pomocą metody o nazwie cancel(). Wywołanie tej metody w czasie gdy klasa jest zajęta może wywołać wyjątek IOException.

6. Czy można anulować bieżącą akcję?

Bieżące zapytanie (a także odpowiedź) można anulować za pomocą metody o nazwie cancel() z poziomu obiektu call:

Call<User> call = retroAPI.getUser(„1”);

call. enqueue(this);

call.cancel();

Przy anulowaniu bieżących akcji należy pamiętać, że skutkuję ono automatycznym wywołaniem metody onFailure(). Aby rozróżnić anulowanie od błędu sieciowego można posłużyć się metodą isCanceled():

@Override

public void onFailure(Call<User> call, Throwable t){

if(call.isCanceled())

System.out.println(„Action cancelled”);

else

t.printStackTrace();

}

7. Jakie zadanie spełnia interfejs Callback?

Implementacja tego interfejsu przekazuje odpowiedzi z serwera. Tylko jedna z metoda tego interfejsu zostaje wywołana w odpowiedzi na określone żądanie. Domyślnie metody są wywoływane w głównym wątku aplikacji (UI) w przypadku platformy Android lub wątku tła, który wykonuje żądanie w przypadku standardowej Javy. Interfejs ten zawiera dwie metody onResponse() i onFailure(). Pierwsza przyjmuje dwa argumenty: interfejs Call oraz Response. Druga metoda też przyjmuje dwa argumenty Call i Throwable. Jest wywoływana gdy zachodzi sieciowy wyjątek lub gdy zdarzy się nieoczekiwany wyjątek podczas tworzenia zapytania lub przetwarzania odpowiedzi.

8. Czy można uprościć pobieranie wyników zapytania?

W małych projektach lub przy niewielkiej liczbie metod serwisowych zamiast tworzyć osobną klasę można posłużyć się anonimową implementacją interfejsu Callback i przetworzyć odpowiedź:

RetroAPI retroAPI = retrofit.create(RetroAPI.class);

Call<User> call = retroAPI.getUser(„1”);

call. enqueue(new Callback<User>(){

@Override

public void onResponse(Call<User> call,

Response<User> response){}

@Override

public void onFailure(Call<User> call, Throwable t){}});

}

9. Jaka jest różnica między anotacją @JsonProperty a @SerializedName?

Obie anotacje mają takie samo znaczenie. Jedyna różnica to, że pochodzą z różnych pakietów. Anotacja @JsonProperty pochodzi z biblioteki Jackson, natomiast @SerializedName z biblioteki Gson. Mogą one być użyte na polach klasy, która ma być serializowana do obiektu JSON i odwrotnie. Ich zadaniem jest zmiana nazwy pola, a użycie opcjonalne, bowiem bez nich klucze w obiekcie JSON otrzymają nazwy pól. Przykładowo taka klasa:

public class Mother {

private int id;

private String name;

private String surname;

}

zapewni taki obiekt JSON:

{

id: 1,

Przeczytałeś bezpłatny fragment.
Kup książkę, aby przeczytać do końca.