I would like to implement REST client with Kotlin Coroutine and Retrofit, but it was difficutl to find a sample that works with current environment. So I struggled to create a sample and now it works so I leave it here. You can find the entire project in GitHub.

The project uses Retrofit2. , Glide, ButterKnife, and Timber also.

Library Versions

The libraries used are below. Coroutine, Retrofit2, Moshi, Glide, ButterKnife, and Timber are used.

dependencies {
// Coroutine
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${CoroutineVersion}"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${CoroutineVersion}"

// Coroutine Adapter
implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:${CoroutineAdapterVersion}"

// Retrofit2
implementation "com.squareup.retrofit2:retrofit:${RetrofitVersion}"
implementation "com.squareup.retrofit2:converter-moshi:${RetrofitVersion}"

// Moshi
implementation "com.squareup.moshi:moshi:${MoshiVersion}"
kapt "com.squareup.moshi:moshi-kotlin-codegen:${MoshiVersion}"

// Glide
implementation "com.github.bumptech.glide:glide:${GlideVersion}"
implementation "com.github.bumptech.glide:okhttp3-integration:${GlideVersion}"
kapt "com.github.bumptech.glide:compiler:${GlideVersion}"
annotationProcessor "com.github.bumptech.glide:compiler:${GlideVersion}"

// ButterKnife
implementation "com.jakewharton:butterknife:${ButterKnifeVersion}"
kapt "com.jakewharton:butterknife-compiler:${ButterKnifeVersion}"
annotationProcessor "com.jakewharton:butterknife-compiler:${ButterKnifeVersion}"

// Timber
implementation "com.jakewharton.timber:timber:${TimberVersion}"}

The library versions are below.

ext {
CoroutineVersion = '1.1.1'
CoroutineAdapterVersion = '0.9.2'
RetrofitVersion = '2.5.0'
MoshiVersion = '1.8.0'
TimberVersion = '4.7.1'
GlideVersion = '4.9.0'
ButterKnifeVersion = '10.1.0'
}

Kotlin version is 1.3.20.

buildscript {
ext.kotlin_version = '1.3.20'
}

Setup Project

Setup Timber in custom Application class.

class MyApplication: Application() {
override fun onCreate() {
super.onCreate()

if (BuildConfig.DEBUG) {
Timber.plant(Timber.DebugTree())
}
}
}

Also, register custom Application and obtain permission of internet access in the manifest file.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.okuzawats.retrofitwithcoroutine">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>

<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

</manifest>

Implement Rest Client

Define response class using data class. To convert snakecase to camelcase, used @JsonClass and @Json annotations of Moshi.

@JsonClass(generateAdapter = true)
data class GitHubUser(
val name: String,
val id: String,
@Json(name = "avatar_url")
val avatarUrl: String
)

See also:

Define Retrofit2 interface. It returns Deffered. This needed by Coroutine.

@GET("users/{user_name}")
fun fetchUserAsync(@Path("user_name") userName: String): Deferred<GitHubUser>

Create the instance of Retrofit2. It uses CoroutineCallAdapter as CallAdapter.

companion object {
val instance: GitHubApi = Retrofit.Builder()
.baseUrl(BuildConfig.BASE_URL)
.addConverterFactory(MoshiConverterFactory.create(Moshi.Builder().build()))
.addCallAdapterFactory(CoroutineCallAdapterFactory())
.build()
.create(GitHubApi::class.java)
}

Now you can access REST API. Create request and wait the response by await.

private fun accessApi() {
GlobalScope.launch(Dispatchers.Main) {
val request = GitHubApi.instance.fetchUserAsync("okuzawats")
try {
val response = request.await()
setImage(response)
} catch (e: Throwable) {
Timber.e(e)
}
}
}

private fun setImage(gitHubUser: GitHubUser) {
Glide.with(CoroutineApplication.applicationContext())
.load(gitHubUser.avatarUrl)
.into(imageView)
}

The entire code is on GitHub, please check it out.