LukasLechnerDev / Kotlin-Coroutines-and-Flow-UseCases-on-Android

๐ŸŽ“ Learning Kotlin Coroutines and Flows for Android by example. ๐Ÿš€ Sample implementations for real-world Android use cases. ๐Ÿ›  Unit tests included!

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Main or IO thread

w201 opened this issue ยท comments

commented

According to this code your network request will be made in MainThread. Isn't it?

`class PerformSingleNetworkRequestViewModel(
private val mockApi: MockApi = mockApi()
) : BaseViewModel() {

fun performSingleNetworkRequest() {
    uiState.value = UiState.Loading
    viewModelScope.launch {
        try {
            val recentAndroidVersions = mockApi.getRecentAndroidVersions()
            uiState.value = UiState.Success(recentAndroidVersions)
        } catch (exception: Exception) {
            Timber.e(exception)
            uiState.value = UiState.Error("Network Request failed!")
        }
    }
}}`

Maybe need to change it a little bit to launch(Dispatchers.IO) {... and uiState.postValue(...)

Retrofit offers "main-safety" when calling suspend functions like getRecentAndrdoidVersions(). This means that we can call it safely from the main thread and Retrofit switches execution to another thread "internally". More information about main safety in this Google Codelab: https://codelabs.developers.google.com/codelabs/kotlin-coroutines/#4.

Btw. calling Room suspend functions are also main safe.

If you want to dig deeper: As far as I understand, the Coroutine Integration in Retrofit is just a small Wrapper that converts the callback-based API with Callbacks into a coroutine-based API with suspend functions. It does so using the suspendCoroutine{} construct.

If you check out the Release Notes when idiomatic Coroutine support was introduced in v2.6.0, it says "Behind the scenes this behaves as if defined as fun user(...): Call<User> and then invoked with Call.enqueue"

I hope it is clearer now ๐Ÿ˜€

commented

Big thanks for the clean explanation. I newbie in coroutines after reactive all looks a little bit strange and as magic :)

Had the same question when looking at the code, thanks for the explanation.

If the simplicity of the coroutines example relies on Retrofit handling part of the complexity in the background that means the example is not necessarily transferable to other asynchronous operations, right?

It depends on the "asynchronous operation".

If you are using a library that exposes suspend functions, you can do it in the same way as it is a convention that suspend functions are non-blocking and you can assume that the library switches to a background thread internally. This is the case for Room & Retrofit.

If you call a synchronous function (that blocks the thread), you have to switch threads yourself with the withContext() construct.

Asynchronous functions in which you have to pass a callback, can be wrapped with the suspendCoroutine{} construct to be able to call it from a coroutine in an idiomatic way.

Does that make sense or do you need more information?