Comment implémenter Retrofit dans un projet Android via Kotlin ?
Par Clément BROSSETTE
Retrofit, c’est quoi ?
La plupart des applications mobiles consomment des API REST JSON pour récupérer toutes les données nécessaires à leur fonctionnement.
Retrofit est aujourd’hui une des façons les plus simples d’implémenter des appels à des webservices REST.
Il s’agit d’un client REST développé par Jake Wharton ainsi que l’ensemble du staff de Square. Cette librairie est basée elle-même sur le client REST OKHttp (développée encore par Square !) et permet d’implémenter plus facilement et rapidement des requêtes réseau sur Android (Java ou Kotlin).
Retrofit nous évite ainsi d’installer manuellement toutes les parties nécessaires à l’exécution d’une requête, comme par exemple la gestion des réponses JSON ou la création d’une AsyncTask.
Cela permet un gain de temps conséquent et un code plus clair pour des performances équivalentes.
Depuis, Retrofit 2.6 supporte l’utilisation des coroutines. Cela permet de ne plus utiliser de callback ou la fonction enqueue.
Comment implémenter Retrofit dans un projet Android via Kotlin ?
Pour cet exemple, nous utiliserons https://jsonplaceholder.typicode.com/, qui est une API gratuite fournissant des données de test.
Ajout des permissions dans AndroidManifest.xml
La permission « INTERNET » est requise pour appeler des APIs dans une application Android.
« ACCES_NETWORK_STATE » permet d'identifier l'état de la connexion internet de l'appareil.
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
Implémentation des bibliothèques nécessaires
Pour installer Retrofit, il faut au minimum Java 8 + ou Android API 21 +.
Vous aurez ensuite besoin d’installer les dépendances suivantes en les renseignant dans le fichier build.gradle sous « dependencies ».
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
//Coroutine
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.5'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.5'
ApiClient Object : création d’une instance de Retrofit
Le client Retrofit doit être configuré avec une URL serveur (BASE_URL) ainsi qu’un convertisseur de requêtes. Ce convertisseur va permettre de convertir automatiquement la réponse JSON en objets. Ici, nous utilisons le convertisseur Gson. Il ne faut pas oublier le mot clé lazy, afin de ne pas dupliquer des instances de Retrofit.
package com.example.myapplication
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
object ApiClient {
private const val BASE_URL: String = "https://jsonplaceholder.typicode.com/"
private val gson : Gson by lazy {
GsonBuilder().setLenient().create()
}
private val httpClient : OkHttpClient by lazy {
OkHttpClient.Builder().build()
}
private val retrofit : Retrofit by lazy {
Retrofit.Builder()
.baseUrl(BASE_URL)
.client(httpClient)
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
}
val apiService : ApiService by lazy{
retrofit.create(ApiService::class.java)
}
}
ApiService class : création d’une interface qui regroupe les différents endpoints
On retrouve, sous forme d’annotations, la méthode et la route. Il faudra aussi spécifier le type de réponse afin que Gson puisse la désérialiser.
On remarquera la nécessité de préciser le type de paramètre avec les annotations @Path, @Query et @Body
package com.example.myapplication
import com.example.myapplication.models.Comment
import com.example.myapplication.models.Post
import com.example.myapplication.models.User
import retrofit2.Response
import retrofit2.http.*
interface ApiService {
@GET("users")
suspend fun getUsers(): Response<MutableList<User>>
@GET("posts/{num}")
suspend fun getPostById(@Path("num") num : Int): Response<Post>
@GET("comments")
suspend fun getCommentsByPost(@Query("postId") postId : Int): Response<MutableList<Comment>>
@POST("posts")
suspend fun createPost(@Body post: Post): Response<Post>
}
Les méthodes suivantes sont disponibles :
- @GET
- @POST
- @PUT
- @DELETE
- @PATCH
L’annotation @HEADER est aussi disponible ici pour définir un ou plusieurs headers sur un endpoint.
Les modèles
Ici, nous créons les modèles via des data classes afin de désérialiser les réponses et de stocker nos données. Point important, chaque champ de chaque modèle doit être identique à la réponse (nom et type) afin que la désérialisation de cette dernière fonctionne.
package com.example.myapplication.models
data class User(
val id: Int? = null,
val name: String? = null,
val userName: String? = null,
val email: String? = null,
val address : Address? = null,
val phone: String? = null,
val website: String? = null
)
package com.example.myapplication.models
data class Address(
val street: String? = null,
val suite: String? = null,
val city: String? = null,
val zipCode: String? = null
)
package com.example.myapplication.models
data class Comment (
val postId: Int = 0,
val id: Int = 0,
val name: String? = null,
val email: String? = null,
val body: String? = null
)
package com.example.myapplication.models
data class Post (
val userId: Int = 0,
val id: Int? = null,
val title: String? = null,
val body: String? = null
)
Un cas d’usage dans mainActivity
Pour cette partie, nous utiliserons Coroutine. Coroutine est un utilitaire de Kotlin permettant d’effectuer des tâches asynchrones. Pour cela, nous devons implémenter CoroutineScope qui indiquera où la coroutine devra envoyer les données. Ici, pour cet exemple, ce sera dans MainScope si l’on veut modifier l’affichage de la mainActivity.
Commençons par créer une nouvelle coroutine avec la fonction launch et la restreindre au main thread avec Dispachers.Main.
Le try/catch est là pour remonter les erreurs du client.
Une dernière vérification de la validité de la réponse et vous pourrez utiliser le body pour vos fonctionnalités !
private fun executeCall() {
launch(Dispatchers.Main) {
try {
val response = ApiClient.apiService.getPostById(1)
if (response.isSuccessful && response.body() != null) {
val content = response.body()
//do something
} else {
Toast.makeText(
this@MainActivity,
"Error Occurred: ${response.message()}",
Toast.LENGTH_LONG
).show()
}
} catch (e: Exception) {
Toast.makeText(
this@MainActivity,
"Error Occurred: ${e.message}",
Toast.LENGTH_LONG
).show()
}
}
}
Et voilà ! Vous savez désormais comment implémenter Retrofit dans un projet Android via Kotlin ! À vous le gain de temps, le code plus clair et tout aussi performant.
À très bientôt pour de nouveaux articles Android !
L'équipe AXOPEN