I am calling an Api from a suspend function and after successful execution of it, I need to call another Api (which is also in another suspend function).
suspend fun updateSubscription(body: Map<String, Any>): NetworkResponse<SubscriptionUpdateResponse> =
withContext(Dispatchers.IO) {
val response = networkManager.execute(
networkManager.updateSubscriptionApi(body)
)
val data = response.body()
if (response.isSuccessful) {
fetchSubscriptions() // suspend function which call another api, should run without blocking
}
return@withContext parseNetworkResponse(response, data)
}
I want to call updateSubscriptionApi and after it successful execution, call fetchSubscription without blocking and return updateSubscription result.
For now, fetchSubscription is also blocking updateSubscription. I tried to call updateSubscription in async block like this without any success.
async{ updateSubscription() }
How can I call fetchSubscriptions() without blocking updateSubscription.
Unfortunately, your requirement for the function to be both suspending and launching concurrent work that's still active when the function returns, is considered an anti-pattern in Kotlin and has some difficulties in achieving it.
But first, the simple things:
Are you sure you need the IO dispatcher? You said the network call is suspending, which means non-blocking and doesn't require a dedicated IO dispatcher.
If you do need it (it's actually a blocking call), don't wrap all the code in it, but just that call.
Now, the hard part. To be able to launch a coroutine as well, it's critical to consider which scope you're launching it in. Kotlin strongly recommends to use structured concurrency, which means launching everything in a well-defined scope of your UI element (activity etc.). In your case you must pass the scope explicitly as a parameter to the function. Normally you'd declare it as an extension on CoroutineScope, but that doesn't work for suspending functions due to the naming collision on coroutineContext, which is both a global val and the property of CoroutineScope. That means your code could look as follows:
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
suspend fun updateSubscription(
scope: CoroutineScope,
body: Map<String, Any>
): NetworkResponse<SubscriptionUpdateResponse> {
val response = withContext(Dispatchers.IO) { // only if you need it!
networkManager.execute(networkManager.updateSubscriptionApi(body))
}
if (response.isSuccessful) {
scope.launch { fetchSubscriptions() }
}
return parseNetworkResponse(response, response.body())
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With