Using Retrofit + Coroutines in Kotlin
Tags: kotlin, android, tutorial
Published: 2020-08-24 01:11:30

First of all, what is [Retrofit] (https://square.github.io/retrofit/)?

As its web site says is A type-safe HTTP client for Android and Java ( We are going to use Kotlin...). So, basically is a REST client for Android. It helps us to get and upload data throughout a REST API.

What about coroutines?

On Android, coroutines help to manage long-running tasks that might otherwise block the main thread and cause your app to become unresponsive. 


Now, let's take a look at a basic implementation


First, we need to add some dependencies to our project. Starting with adding the version variables in our *build.gradle(<project name>)*, under *build script*

```Kotlin
buildscript {
    ext {
    version_moshi = "1.8.0"
    version_retrofit = "2.5.0"
    version_retrofit_coroutines_adapter = "0.9.2"
    version_kotlin_coroutines = "1.1.0"
    version_retrofit_coroutines_adapter = "0.9.2"
    }
    …
}
```

Then add the next dependencies to the *build.gradle(:app)* 

```kotlin
//coroutines
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_kotlin_coroutines"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_kotlin_coroutines"
implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$version_retrofit_coroutines_adapter"

//Retrofit

implementation "com.squareup.retrofit2:retrofit:$version_retrofit"
implementation "com.squareup.retrofit2:converter-moshi:$version_retrofit"

//moshi
implementation "com.squareup.moshi:moshi:$version_moshi"
implementation "com.squareup.moshi:moshi-kotlin:$version_moshi"
```

Build your project and now we are ready to start.

In this example, I'm going to use [Advice Slip JSON API] (https://api.adviceslip.com/). More specific **https://api.adviceslip.com/advice** this URL returns a random advice every time you call it. 

Here the JSON we get:

```JSON
{
  "slip": {
    "id": 45,
    "advice": "Build something out of LEGO."
  }
}
```
So first we are going to create a new package named **“network”** in which we are going to add two Kotlin files:

* AdviceProperty.kt
* AdviceApiService.kt

In **AdviceProperty.kt** we are going to add the properties of the JSON in a data-class structure. Like the next example:

```kotlin
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

@Parcelize
data class AdviceProperty(
    val slip: AdviceData
    ): Parcelable

@Parcelize
data class AdviceData (
    val id: Int,
    val advice: String
): Parcelable
```
As you can see, we follow our JSON structure. Our first data-class has a property called **slip** whose type is **AdviceData**, this type is another data class with two properties **id** and **advice**. This is how we can replicate our nested JSON structure.

Then in **AdviceApiService.kt** we are going to set up our Retrofit instance.

```kotlin
import com.jakewharton.retrofit2.adapter.kotlin.coroutines.CoroutineCallAdapterFactory
import com.squareup.moshi.Moshi
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
import kotlinx.coroutines.Deferred
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET


// The base URL where our API is
private const val BASE_URL = "https://api.adviceslip.com/"

/* Moshi Makes it easy to parse JSON into objects 
you can use GSON instead if you want*/

private val moshi = Moshi.Builder()
    .add(KotlinJsonAdapterFactory())
    .build()

//Here is our retrofit instance

private val retrofit = Retrofit.Builder()
    .addConverterFactory(MoshiConverterFactory.create(moshi))
    .addCallAdapterFactory(CoroutineCallAdapterFactory())
    .baseUrl(BASE_URL)
    .build()

//Then we are going to create the interface 
which is going to help to handle our GET method 
to call the API*/

interface AdviceApiService{

    @GET("advice")
    fun getProperty():
            Deferred<AdviceProperty>
}

/* Singleton to create this instance only once 
and get it ready every time we call it. */

object  AdviceApi {
    val retrofitService : AdviceApiService by lazy {
        retrofit.create(AdviceApiService::class.java)
    }
}
```

Alright!, we're almost done!

I'm using the MVVM Architecture, which means for each fragment/activity I have a ViewModel Class in which I manage all the data for my app, and also this API call.

So in the ViewModel (this can be your class), I have a variable named **_properties** which is going to store my data, you can see its type it's **AdviceProperty** (Remember our class in the network package)

```kotlin
private var _properties = MutableLiveData<AdviceProperty>()
```
Next, I have other two variables:

```kotlin
private val viewModelJob = Job()
private val coroutineScope = CoroutineScope( viewModelJob + Dispatchers.Main )
```

The first one is the **Job** which is gonna define the lifecycle of the coroutine scope. So if its children fail, its gonna notify the parent and it will cancel the other children in case we have more instances running.

The second one is our coroutineScope, here we define in which thread our coroutine is going to run.

Then the method who is going to create the coroutine, and also manage the call to the API: getAdviceProperty

```kotlin
private fun getAdviceProperty(){

    coroutineScope.launch { 

        var getProperty = AdviceApi.retrofitService.getProperty()

        try {
            _properties.value =  getProperty.await()

        }catch (e: Exception){
            //library to show logs
            Timber.i("EROR ${e}");
        }
    }
}
```

As you can see here, we have **coroutineScope.launch** this block of code allows us to create a new coroutine and run it in the thread we define previously.

Then we can see in the **getProperty** variable the word **“await”**, this is because our Singleton class returns a **Deferred object** (feature or a promise in java).

If you are using view models do not forget to cancel the **Job** in the **onClear()** method

```kotlin 
override fun onCleared() {
    super.onCleared()
    viewModelJob.cancel()
}
```

And that’s it! We have now our response in a variable and we can use it wherever we want. It is much less code than we use to write with java or without coroutines.

________

Take a look at my repository: [lucky Piñata] (https://github.com/jbc7ag/lucky-pinata) It has a working example of this topic.