Android Retrofit Tutorial et exemples.

Qu'est-ce que Retrofit ? Retrofit est un client HTTP sécurisé créé par Square Inc.

Le rôle de Retrofit est de transformer votre API HTTP en une interface Java :

public interface GitHubService {
  @GET("users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}

Dans ce cours, nous allons nous intéresser à Retrofit et aux exemples de Retrofit dans le cadre du développement android. Nous verrons comment nous pouvons l'utiliser pour parler aux webservices via HTTP d'une manière simple.

Quelles sont les exigences pour Retrofit ?

Retrofit a des exigences très généreuses :

  1. Java 7 et plus.
  2. Android 2.3 et plus.

Comment installer Retrofit ?

Retrofit est une bibliothèque de clients HTTP tiers pour Android et Java. Elle doit donc être installée dans votre projet.

Si vous cherchez une classe de mise en réseau qui est standard et incluse dans le cadre android, consultez HttpURLConnection.

Sinon, Retrofit peut être installé de trois façons :

1. Comme un jar.

En gros, vous téléchargez le jar de Retrofit et vous l'ajoutez à votre android studio comme une bibliothèque jar.

Par exemple, j'ai utilisé Retrofit 2.4.0 qui peut être téléchargé à partir de [ici] (https://repo1.maven.org/maven2/com/squareup/retrofit2/retrofit/2.4.0/retrofit-2.4.0.jar).

Sinon, vous pouvez vérifier la dernière version [ici] (https://square.github.io/retrofit/).

2. Via maven

Maven, également connu sous le nom de Apache Maven, est un outil d'automatisation de la construction utilisé principalement pour les projets Java.

Cela lui confère deux rôles principaux :

  1. Décrire la façon dont un projet est construit.
  2. Décrire les dépendances du projet.

Bien nous pouvons décrire Retrofit comme notre dépendance dans un projet java.

<dependency>
  <groupId>com.squareup.retrofit2</groupId>
  <artifactId>retrofit</artifactId>
  <version>2.4.0</version>
</dependency>

3. Via Gradle

Gradle est un système de construction utilisé par android studio.

Si vous créez un projet android, il y a de fortes chances que vous utilisiez cette méthode pour installer retrofit. En effet, vous utiliserez probablement [Android Studio] (https://camposha.info/android/android-studio), car il s'agit de l'IDE de développement officiel pour android. Et Android Studio utilise le système de construction Gradle.

Dans ce cas, vous devrez vous rendre au niveau de votre application build.gradle et ajouter l'instruction suivante dans votre DSL de dépendances :

implementation 'com.squareup.retrofit2:retrofit:2.4.0'

Interfaces, classes et méthodes communes de Retrofit.

1. Call

Il s'agit d'une interface Retrofit qui représente une invocation d'une méthode Retrofit qui envoie une requête à un serveur web et renvoie une réponse. Comme son nom l'indique, elle représente essentiellement un appel HTTP que vous effectuez.

Chaque appel donne lieu à sa propre paire requête et réponse HTTP. Il est possible d'effectuer plusieurs appels avec les mêmes paramètres. Cependant, vous utilisez le clone pour y parvenir. Vous pouvez l'utiliser pour mettre en œuvre l'interrogation ou pour réessayer un appel qui a échoué.

Lorsque vous effectuez des appels HTTP, vous pouvez les faire de manière synchrone ou asynchrone. Pour effectuer des appels synchrones, vous utilisez la méthode execute(). Par contre, pour effectuer des appels asynchrones, vous utilisez la méthode enqueue().

Si vous voulez annuler un appel, utilisez la méthode cancel().

Voici sa définition :

public interface Call<T> extends Cloneable

Notez que dans ce cas, T représente le type d'un corps de réponse réussi.

2. enqueue()

C'est une méthode qui appartient à l'interface Call<T>. Nous avons parlé de cette interface qui représente un appel HTTP que vous faites.

Et normalement, vous pouvez faire un appel ou une requête synchrone ou asynchrone. Si vous voulez faire un appel asynchrone, vous utilisez cette méthode.

Voici sa définition :

public abstract void enqueue(retrofit2.Callback<T> callback)

Cette méthode va alors envoyer de manière asynchrone votre requête et notifier le callback de sa réponse au cas où une erreur se serait produite en parlant au serveur, en créant la requête ou en traitant la réponse.

Voici un exemple d'utilisation simple :

        Call<List<Spacecraft>> call = myAPIService.getSpacecrafts();
        call.enqueue(new Callback<List<Spacecraft>>() {

            @Override
            public void onResponse(Call<List<Spacecraft>> call, Response<List<Spacecraft>> response) {
                myProgressBar.setVisibility(View.GONE);
                populateRecyclerView(response.body());
            }
            @Override
            public void onFailure(Call<List<Spacecraft>> call, Throwable throwable) {
                myProgressBar.setVisibility(View.GONE);
                Toast.makeText(MainActivity.this, throwable.getMessage(), Toast.LENGTH_LONG).show();
            }
        });

3. Callback

Il s'agit d'une interface définissant les méthodes responsables de la communication des réponses d'un serveur ou des demandes hors ligne.

Voici sa définition :

public interface Callback<T>

Le T dans l'exemple ci-dessus représente un type de corps de réponse réussi.

Normalement, une seule méthode est appelée en réponse à une requête donnée. Cette méthode sera exécutée en utilisant l'exécuteur de callback de Retrofit. Si vous n'en spécifiez pas, les valeurs par défaut suivantes sont utilisées :

  1. Android : Les callbacks sont exécutés sur le thread principal (UI) de l'application.
  2. JVM : Les callbacks sont exécutés sur le thread d'arrière-plan qui a effectué la requête.

Voici un exemple d'utilisation :

new Callback<List<Spacecraft>>() {

            @Override
            public void onResponse(Call<List<Spacecraft>> call, Response<List<Spacecraft>> response) {
                myProgressBar.setVisibility(View.GONE);
                populateRecyclerView(response.body());
            }
            @Override
            public void onFailure(Call<List<Spacecraft>> call, Throwable throwable) {
                myProgressBar.setVisibility(View.GONE);
                Toast.makeText(MainActivity.this, throwable.getMessage(), Toast.LENGTH_LONG).show();
            }
        }

4. Rétrofit

Il s'agit d'une classe chargée d'adapter une interface Java aux appels HTTP en utilisant des annotations sur les méthodes déclarées pour définir la façon dont les demandes sont effectuées.

Voici sa définition

public final class Retrofit extends Object

Pour l'utiliser, vous devrez créer son instance. Cependant vous faites cela en utilisant le builder et en passant votre interface à create pour générer une implémentation. Par exemple :

   Retrofit retrofit = new Retrofit.Builder()
       .baseUrl("https://api.example.com/")
       .addConverterFactory(GsonConverterFactory.create())
       .build();

   MyApi api = retrofit.create(MyApi.class);
   Response<User> user = api.getUser().execute();

Ou je peux créer une classe de fabrique simple pour me retourner ses instances :

    static class RetrofitClientInstance {

        private static Retrofit retrofit;
        private static final String BASE_URL = "https://raw.githubusercontent.com/";

        public static Retrofit getRetrofitInstance() {
            if (retrofit == null) {
                retrofit = new Retrofit.Builder()
                        .baseUrl(BASE_URL)
                        .addConverterFactory(GsonConverterFactory.create())
                        .build();
            }
            return retrofit;
        }
    }

Ensuite, j'utilise cette classe de cette façon :

        MyAPIService myAPIService = RetrofitClientInstance.getRetrofitInstance().create(MyAPIService.class);

Kotlin Android Retrofit Movies Exemple

Dans cet exemple, vous verrez comment récupérer une liste de films du site IMDB et la rendre dans une vue recyclée. Les éléments sont récupérés via Retrofit. Les images sont rendues via Picasso.

Voici l'image de démonstration :

Etape 1 : Créer le projet

Commencez par créer un projet Android Studio vide.

Étape 2 : Dépendances

Tout d'abord, nous allons ajouter Retrofit comme une dépendance, à côté du converter-gson de Retrofit :

    implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
    implementation "com.squareup.retrofit2:converter-gson:$retrofitConverterGsonVer"

Nous allons également ajouter des dépendances pour RecyclerView et CardView :

    implementation "androidx.recyclerview:recyclerview:$supportVer"
    implementation "androidx.cardview:cardview:$supportVer"

Nous ajouterons également une dépendance pour Picasso, notre imageloader :

    implementation "com.squareup.picasso:picasso:$picassoVersion"

Étape 3 : Conception de la mise en page

Ensuite, nous allons concevoir nos mises en page. Nous aurons deux mises en page :

(a). list_row.xml

Ceci sera gonflé en une seule ligne dans notre vue recyclée. Nous aurons un cardview avec une image et du texte :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <androidx.cardview.widget.CardView
        android:id="@+id/card_view"
        android:layout_width="match_parent"
        android:layout_height="240dp"
        android:layout_gravity="center"
        android:layout_margin="5dp"
        android:background="#fff"
        card_view:cardCornerRadius="2dp"
        card_view:contentPadding="10dp">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <ProgressBar
                android:id="@+id/progress_bar"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:visibility="gone" />

            <ImageView
                android:id="@+id/image_view_movie"
                android:layout_width="match_parent"
                android:layout_height="0dp"
                android:layout_weight="1"
                android:scaleType="fitXY" />

            <TextView
                android:id="@+id/movie_title"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginStart="10dp"
                android:textColor="@android:color/black"
                android:textSize="18sp"
                android:textStyle="bold" />

        </LinearLayout>

    </androidx.cardview.widget.CardView>

</LinearLayout>

(b). activité_main.xml

Dans notre layout MainActivity, nous ajouterons un recyclerview qui rendra notre liste d'éléments :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.developers.usingretrofit.MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/movie_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_gravity="center"
        android:layout_marginEnd="5dp"
        android:layout_marginStart="5dp" />
</LinearLayout>

Étape 4 : Créer des constantes

Une constante est une variable dont la valeur ne change pas. Nous aurons besoin de telles variables par exemple pour l'URL de base et l'URL de l'image dans notre projet. Créez un fichier appelé Constants.kt et ajoutez le code suivant :

Constants.kt

class Constants {

    companion object {
        @JvmField
        val BASE_URL = "https://api.themoviedb.org/3/movie/";
        @JvmField
        val IMAGE_BASE_URL = "http://image.tmdb.org/t/p/w185/"
    }

}

Étape 5 : Créer des classes de modèle

Nous aurons deux classes de modèle :

(a). MovieResult.kt

C'est une classe qui représentera un appel de résultat de film. Cette classe de modèle aura des propriétés comme page, total des résultats, total des pages ainsi que la liste des résultats :

import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

data class MovieResult(@SerializedName("page")
                  @Expose
                  var page: Int? = null,
                  @SerializedName("total_results")
                  @Expose
                  var totalResults: Int? = null,
                  @SerializedName("total_pages")
                  @Expose
                  var totalPages: Int? = null,
                  @SerializedName("results")
                  @Expose
                  var results: List<Result>? = null)

(b). Resultat.kt

Cette classe de résultat représente un seul film ainsi que ses propriétés comme le titre, la popularité, les ID de genre, etc :


import com.google.gson.annotations.Expose
import com.google.gson.annotations.SerializedName

data class Result(
        @SerializedName("vote_count")
        @Expose
        var voteCount: Int? = null,
        @SerializedName("id")
        @Expose
        var id: Int? = null,
        @SerializedName("video")
        @Expose
        var video: Boolean? = null,
        @SerializedName("vote_average")
        @Expose
        var voteAverage: Double? = null,
        @SerializedName("title")
        @Expose
        var title: String? = null,
        @SerializedName("popularity")
        @Expose
        var popularity: Double? = null,
        @SerializedName("poster_path")
        @Expose
        var posterPath: String? = null,
        @SerializedName("original_language")
        @Expose
        var originalLanguage: String? = null,
        @SerializedName("original_title")
        @Expose
        var originalTitle: String? = null,
        @SerializedName("genre_ids")
        @Expose
        var genreIds: List<Int>? = null,
        @SerializedName("backdrop_path")
        @Expose
        var backdropPath: String? = null,
        @SerializedName("adult")
        @Expose
        var adult: Boolean? = null,
        @SerializedName("overview")
        @Expose
        var overview: String? = null,
        @SerializedName("release_date")
        @Expose
        var releaseDate: String? = null)

Étape 6 : Créer un service API

Il s'agit simplement d'une interface qui contiendra une méthode qui représente notre requête HTTP :

ApiInterface.kt


import com.developers.usingretrofit.model.MovieResult
import com.developers.usingretrofit.utils.Constants
import retrofit2.Call
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import retrofit2.http.GET
import retrofit2.http.Query

interface ApiInterface {

    @GET("popular")
    fun getMovies(@Query("api_key") key: String,
                  @Query("page") page: Int): Call<MovieResult>

    companion object Factory {

        fun create(): ApiInterface {

            val retrofit = Retrofit.Builder()
                    .addConverterFactory(GsonConverterFactory.create())
                    .baseUrl(Constants.BASE_URL)
                    .build()

            return retrofit.create(ApiInterface::class.java);

        }

    }

}

Step 7 : Créer un adaptateur

Pour rendre notre liste de films dans notre recyclerview nous avons besoin d'un adaptateur. Créez-en un en étendant le RecyclerView.Adapter comme indiqué ci-dessous :

MovieAdapter.kt

import android.content.Context
import android.net.Uri
import androidx.recyclerview.widget.RecyclerView
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.developers.usingretrofit.R
import com.developers.usingretrofit.model.Result
import com.developers.usingretrofit.utils.Constants
import com.squareup.picasso.Callback
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.list_row.view.*

class MovieAdapter(val context: Context, private val resultList: List<Result>?) : RecyclerView.Adapter<MovieAdapter.MyViewHolder>() {

    override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
        holder.bindItems(resultList?.get(position))
    }

    override fun getItemCount(): Int {
        return resultList?.size!!
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
        val view = LayoutInflater.from(context).inflate(R.layout.list_row, parent, false)
        return MyViewHolder(view)
    }

    class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(result: Result?) {
            itemView.movie_title.text = result?.title
            val posterUri = Uri.parse(Constants.IMAGE_BASE_URL).buildUpon()
                    .appendEncodedPath(result?.posterPath)
                    .build()
            itemView.progress_bar.visibility = View.VISIBLE
            Picasso.with(itemView.context).load(posterUri.toString())
                    .into(itemView.image_view_movie, object : Callback {

                        override fun onError() {
                            //Show Error here
                        }

                        override fun onSuccess() {
                            itemView.progress_bar.visibility = View.GONE
                        }

                    })
        }
    }
}

Étape 8 : Écrire le code de l'activité principale (MainActivity)

Voici le code complet de la MainActivity :

import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.recyclerview.widget.GridLayoutManager
import com.developers.usingretrofit.adapter.MovieAdapter
import com.developers.usingretrofit.model.MovieResult
import kotlinx.android.synthetic.main.activity_main.*
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val apiCall = ApiInterface.create()
        apiCall.getMovies(BuildConfig.TV_KEY, 1).enqueue(object : Callback<MovieResult> {
            override fun onFailure(call: Call<MovieResult>?, t: Throwable?) {
                showError(t?.message)
            }

            override fun onResponse(call: Call<MovieResult>?, response: Response<MovieResult>?) {
                val movieResponse = response?.body()
                val resultList = movieResponse?.results
                val layoutManager = GridLayoutManager(applicationContext,2)
                val adapter = MovieAdapter(applicationContext, resultList)
                movie_recycler_view.layoutManager = layoutManager
                movie_recycler_view.adapter = adapter
            }

        })
    }

    private fun showError(message: String?) {
        toast(message.toString())
    }

    fun Context.toast(msg: String) {
        Toast.makeText(applicationContext, msg, Toast.LENGTH_SHORT).show()
    }
}

Exécuter

Copier le code ou le télécharger dans le lien ci-dessous, construire et exécuter.

Référence

Voici les liens de référence :

Numéro Lien
1. Télécharger Exemple
2. Suivre auteur du code
3. Code : Licence Apache 2.0

Catégorisé: