In this article, I’ll demonstrate how to use coroutine in order to - Chain multiple network request - Create parallel network requests and process the responses when all of them are finished.
Coroutines simplify asynchronous programming by putting the complications into libraries. The logic of the program can be expressed sequentially in a coroutine, and the underlying library will figure out the asynchrony for us.
launch- Launches new coroutine without blocking current thread and returns a reference to the coroutine as a Job. The coroutine is canceled when the resulting job is cancelled.
async- Creates new coroutine and returns its future result as an implementation of Deferred. The running coroutine is canceled when the resulting object is cancelled.
launch {
delay(2000)
println("launch block")
}
val result: Deferred<String> = async {
delay(3000)
"async block"
}
println(result.await())
dependencies {
// Retrofit
implementation "com.squareup.retrofit2:retrofit:$latestRetrofitVersion"
implementation "com.squareup.retrofit2:converter-gson:$latestRetrofitVersion"
// OKHttp
implementation "com.squareup.okhttp3:okhttp:$okHttpVersion"
implementation "com.squareup.okhttp3:logging-interceptor:$okHttpVersion"
implementation "com.squareup.okhttp3:okhttp-urlconnection:$okHttpVersion"
// Kotlin & Coroutines
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion"
// For Viewmodel to work with Coroutine
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleViewmodelKtxVersion"
}
interface SomeApi {
@GET("path1/")
fun getObject1(): Call<Object1>
@GET("path2/")
fun getObject2(): Call<Object2>
@GET("path3/{id}")
fun getObject3(@Path("id") objectId : String): Call<Object3>
}
interface SomeApi {
@GET("path1/")
suspend fun getObject1(): Response<Object1>
@GET("path2/")
suspend fun getObject2(): Response<Object2>
@GET("path3/{id}")
suspend fun getObject3(@Path("id") objectId : String): Response<Object3>
}
object Api {
fun getApiService(): SomeApi {
val gson = GsonBuilder().create()
return Retrofit.Builder()
.baseUrl(baseUrl)
.client(provideOkHttpClient(provideLoggingInterceptor()))
.addConverterFactory(GsonConverterFactory.create(gson))
.build().create(SomeApi::class.java)
}
private fun provideOkHttpClient(interceptor: HttpLoggingInterceptor): OkHttpClient {
val b = OkHttpClient.Builder()
b.addInterceptor(interceptor)
return b.build()
}
private fun provideLoggingInterceptor(): HttpLoggingInterceptor {
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
return interceptor
}
}
class SomeRepository(val apiService: SomeApi) {
suspend fun getObject1(): Response<Object1> = apiService.getObject1()
suspend fun getObject2(): Response<Object2> = apiService.getObject2()
suspend fun getObject3(objectId : String): Response<Object3> = apiService.getObject3((objectId)
}
class SomeViewModel(
private val repository: SomeRepository
) : ViewModel() {
fun chainingRequest() {
viewModelScope.launch {
val object1 = repository.getObject1().body()
val object3 = repository.getObject3(object1.id).body()
processObject3(object3)
}
}
}
class SomeViewModel(
private val repository: SomeRepository
) : ViewModel() {
fun parallelRequest() {
viewModelScope.launch {
try {
val getObject1Task = async { apiService.getObject1() }
val getObject2Task = async { apiService.getObject2() }
processData(getObject1Task.await().body(), getObject2Task.await().body())
} catch (exception: Exception) {
Log.e("TAG", exception.message)
}
}
}
}
From us to your inbox weekly.