Welkom bij de Retrofit Android Voorbeeld Tutorial. Vandaag zullen we de Retrofit-bibliotheek gebruiken die is ontwikkeld door Square om REST API-aanroepen in onze Android-applicatie te verwerken.
Retrofit Android
Retrofit is een typeveilige REST-client voor Android en Java, die tot doel heeft het gemakkelijker te maken om RESTful webservices te consumeren. We zullen niet ingaan op de details van Retrofit 1.x-versies en direct overstappen naar Retrofit 2, dat veel nieuwe functies heeft en een gewijzigde interne API in vergelijking met de vorige versies. Retrofit 2 maakt standaard gebruik van OkHttp als de netwerklaag en is erop gebouwd. Retrofit serialiseert automatisch de JSON-response met behulp van een POJO (Plain Old Java Object) die vooraf moet worden gedefinieerd voor de JSON-structuur. Om JSON te serialiseren hebben we een converter nodig om het eerst in Gson om te zetten. We moeten de volgende afhankelijkheden toevoegen aan ons build.gradle
-bestand.
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'
De OkHttp-afhankelijkheid wordt al meegeleverd met de Retrofit 2-afhankelijkheid. Als je een afzonderlijke OkHttp-afhankelijkheid wilt gebruiken, moet je de OkHttp-afhankelijkheid uitsluiten van Retrofit 2 zoals hieronder:
compile ('com.squareup.retrofit2:retrofit:2.1.0') {
// sluit de OkHttp-afhankelijkheidsmodule van Retrofit uit en definieer je eigen 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'
- De logging-interceptor genereert een log-string van de volledige response die wordt geretourneerd.
- Er zijn ook andere converters om de JSON naar het vereiste type te parsen. Een paar daarvan worden hieronder vermeld.
- 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
Voeg de toestemming toe om toegang te krijgen tot internet in het bestand AndroidManifest.xml.
OkHttp Interceptors
Interceptors zijn een krachtig mechanisme aanwezig in OkHttp die oproepen kunnen controleren, herschrijven en opnieuw proberen. Interceptors kunnen grofweg worden verdeeld in twee categorieën:
- Applicatie-interceptors: Om een applicatie-interceptor te registreren, moeten we
addInterceptor()
aanroepen opOkHttpClient.Builder
- Netwerk-interceptors: Om een netwerk-interceptor te registreren, roep
addNetworkInterceptor()
aan in plaats vanaddInterceptor()
Configureren van de Retrofit-interface
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;
}
}
De methode getClient()
in de bovenstaande code wordt telkens aangeroepen bij het instellen van een Retrofit-interface. Retrofit voorziet in een lijst van annotaties voor elk van de HTTP-methoden: @GET, @POST, @PUT, @DELETE, @PATCH of @HEAD
. Laten we eens kijken hoe onze klasse APIInterface.java
eruitziet.
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);
}
In de bovenstaande klasse hebben we enkele methoden gedefinieerd die HTTP-verzoeken uitvoeren met annotaties. @GET("/api/unknown")
roept doGetListResources();
aan. doGetListResources()
is de naam van de methode. MultipleResource.java
is een Model-POJO-klasse voor ons responsobject dat wordt gebruikt om de responsparameters naar hun respectievelijke variabelen te mappen. Deze POJO-klasse fungeert als het retourtype van de methode. Een eenvoudige POJO-klasse voor MultipleResources.java
wordt hieronder gegeven.
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;
}
}
De annotatie @SerializedName
wordt gebruikt om de naam van het veld in de JSON-response op te geven. Bekijk de POJO-klasse en kopieer deze naar de structuur van je Android Studio-project. De POJO-klassen worden ingepakt in een getypeerde Retrofit-klasse
Call
. Opmerking: Een JSONArray wordt geserialiseerd als een lijst van objecten in de POJO-klassen. Methodeparameters: Er zijn een groot aantal mogelijke opties van parameters om binnen een methode door te geven:
@Body
– Verzendt Java-objecten als verzoeklichaam.@Url
– gebruik dynamische URL’s.@Query
– We kunnen eenvoudig een methodeparameter toevoegen met @Query en een query-parameter naam, waarbij het type wordt beschreven. Om een query URL-gecodeerd te maken, gebruiken we het formulier:@Query(value = "auth_token", encoded = true) String auth_token
@Field
– verzend gegevens als formulier-gecodeerd. Hiervoor is een@FormUrlEncoded
annotatie vereist die is gekoppeld aan de methode. De@Field
parameter werkt alleen met een POST
Opmerking: @Field vereist een verplichte parameter. In gevallen waarin @Field optioneel is, kunnen we in plaats daarvan @Query gebruiken en een null-waarde doorgeven.
Retrofit Android voorbeeldprojectstructuur
Het pojo-pakket definieert vier modelklassen voor elk van de API-eindpuntreacties die zijn gedefinieerd in de klasse 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;
}
}
De bovenstaande klasse wordt gebruikt om de responsbody te maken voor de methode 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;
}
De MainActivity.java
is waar we elk van de API-eindpunten oproepen die gedefinieerd zijn in de Interface-klasse en elk van de velden weergeven in een 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);
wordt gebruikt om de APIClient te instantiëren. Om de Model-klasse aan de respons te koppelen, gebruiken we: MultipleResource resource = response.body();
Het uitvoeren van de toepassing zou elk van de eindpunten aanroepen en een Toast-bericht ervoor weergeven. Hiermee komt een einde aan de Retrofit Android-voorbeeldzelfstudie. U kunt het voorbeeldproject voor Android Retrofit downloaden vanaf de onderstaande link.
Source:
https://www.digitalocean.com/community/tutorials/retrofit-android-example-tutorial