Cómo usar Retrofit en android con Kotlin (KDA 21)
Antonio Leiva

Este es sólo un ejemplo más de que en Kotlin podemos seguir usando las mismas librerías que siempre hemos utilizado en Java para Android.

Retrofit es una librería que simplifica muchísimo la generación de peticiones contra un API, y en este caso te voy a enseñar cómo integrarla con algunas peticiones del API de LastFM. Puedes ver el código completo funcionando en el repositorio de Bandhook Kotlin.

¿Te gustaría comenzar hoy a dar el siguiente paso? Te recomiendo que entres en mi training gratuito aquí

Retrofit 2 en Kotlin

El código en Kotlin va a ser muy parecido a lo que usaríamos en Java. Veremos más en detalle cuáles son algunas de sus diferencias, pero verás que todo es bastante sencillo e intuitivo.

Y también crearemos alguna función de extensión muy útil, ya veras.

Configuración del build.gradle

Tampoco entraré mucho en esto, pero puedes añadir las siguientes instrucciones al build.gradle:

compile "com.squareup.okhttp3:okhttp:$okhttpVersion"
compile "com.squareup.okhttp3:logging-interceptor:$okhttpVersion"

compile ("com.squareup.retrofit2:retrofit:$retrofitVersion"){
    // exclude Retrofit’s OkHttp peer-dependency module and define your own module import
    exclude module: 'okhttp'
}
compile "com.squareup.retrofit2:converter-gson:$retrofitVersion"

Las primeras dependencias incluyen la última versión de OkHttp y un interceptor que sirve para hacer logging, que puede ser útil para depurar.

Las siguientes añaden Retrofit (excluyendo OkHttp, para que tengamos control sobre la versión que usamos), y el conversor de Gson para convertir las peticiones a clases.

Crea la interfaz de comunicación

Esta es la parte neurálgica de Retrofit. Es donde se especifica la estructura de las peticiones, que tendrá que coincidir con la de la API:

interface LastFmService {

    @GET("/2.0/?method=artist.search")
    fun searchArtist(@Query("artist") artist: String): Call

    @GET("/2.0/?method=artist.getinfo")
    fun requestArtistInfo(@Query("mbid") id: String, @Query("lang") language: String): Call

    @GET("/2.0/?method=artist.gettopalbums")
    fun requestAlbums(@Query("mbid") id: String, @Query("artist") artist: String): Call;

    @GET("/2.0/?method=artist.getsimilar")
    fun requestSimilar(@Query("mbid") id: String): Call

    @GET("/2.0/?method=album.getInfo")
    fun requestAlbum(@Query("mbid") id: String): Call
}

No tiene mucha historia. Se identifica el tipo de la petición con la notación, y luego los parámetros de la petición como argumentos de la función.

En Retrofit 2, necesitamos devolver objetos del tipo Call.

Inicialización del servicio de comunicación

Primero puedes inicializar el cliente de OkHttp de la siguiente forma:

val client = OkHttpClient().newBuilder()
    .cache(cache)
    .addInterceptor(LastFmRequestInterceptor(apiKey, cacheDuration))
    .addInterceptor(HttpLoggingInterceptor().apply {
        level = if (BuildConfig.DEBUG) Level.BODY else Level.NONE
    })
    .build()
}

Aquí podemos ver la utilización de la función, apply, que nos ayudará a inicializar el interceptor al estilo de un builder, sin necesidad de que la clase implemente ningún tipo de builder.

El LastFmRequestInterceptor no tiene nada muy destacable, pero le puedes echar un ojo en Github. Nada especial tampoco en la creación del servicio:

val retrofit = Retrofit.Builder()
        .baseUrl("http://ws.audioscrobbler.com")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

val lastFmService = retrofit.create(LastFmService::class.java)

Haz tu primera petición

Debido a la necesidad de las Call en Retrofit 2, se vuelve un poco más tedioso el código:

val call = lastFmService.requestAlbums(mbid, name)
val result = call.execute().body()
val albums = AlbumMapper().transform(result.topAlbums.albums)

Sin embargo, gracias a las funciones de extensión, nos podemos crear una función sobre Call que nos recupere los valores, de esta forma:

val albums = lastFmService.requestAlbums(mbid, name).unwrapCall { 
    AlbumMapper().transform(topAlbums.albums)
}

Mucho más sencillo, ¿verdad?

¿Cuál es la forma de unwrapCall?

inline fun <T, U> Call.unwrapCall(f: T.() -> U): U = execute().body().f()

Es una función que extiende a Call, y que lo que hace es ejecutar la petición, recuperar el body, y hacer que éste (que será de tipo U) ejecute la función f().

En el ejemplo de arriba T es LastFmResponse y U es List.

Conclusión

Con este ejemplo te quería demostrar una vez más que cualquiera de las librerías Java que conoces puede ser utilizada en Kotlin sin problema.

También que, lejos de suponer una complicación, en la mayoría de los casos el lenguaje nos hará las cosas incluso más sencillas.

Anímate y vente al training gratuito, donde te contaré todo lo que necesitas para aprender a crear tus Apps Android en Kotlin desde cero. Descúbrelo todo sobre el lenguaje del futuro.

Quizá también te interese…

2 formas de recolectar Flows en la UI que SÍ funcionan

2 formas de recolectar Flows en la UI que SÍ funcionan

En la serie de artículos sobre Programación Reactiva con Flow hemos visto muchos conceptos, y hemos aprendido cómo aplicarlos al desarrollo Android. Pero hay algo que no hemos hecho del todo bien. Esto es la recolección de Flows desde la Activity (o el Fragment, en...

Cómo hacer tests de Corrutinas y Flows – Paso a Paso

Cómo hacer tests de Corrutinas y Flows – Paso a Paso

¡Vaya viaje por el que hemos pasado en estos artículos! Hace ya varios de ellos empezamos hablando sobre la programación reactiva con Flow, y hemos aprendido un montón de conceptos e ideas sobre cómo aplicarlos en el día a día. Pero nada de esto está completo si no...

Convertir cualquier callback en un Flow con CallbackFlow

Convertir cualquier callback en un Flow con CallbackFlow

Existen varios tipos de Flows muy particulares que nos van a solucionar la vida cuando tengamos que hacer cosas muy concretas. Ya vimos StateFlow en un artículo anterior, y en esta ocasión hablamos de CallbackFlow ¿Qué es CallbackFlow? Es un tipo de Flow que nos...