Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

usecase4/VariableAmountOfNetworkRequestsViewModel#performNetworkRequestsConcurrently crashes on exception #8

Open
lgtout opened this issue Jan 31, 2021 · 3 comments

Comments

@lgtout
Copy link

lgtout commented Jan 31, 2021

Hi, Lukas!

I think there's a problem with the solution for

usecase4/VariableAmountOfNetworkRequestsViewModel#performNetworkRequestsConcurrently.

It crashes when I configure MockApi to return a 500 on the call to http://localhost/android-version-features/28.

Reading this about exceptions, it seems like try-catch will not catch the exception because async is not the direct child of the scope - launch is. So async will propagate the exception up to its parent (launch) and launch will throw the exception.

What do you think?

- Julian

@lgtout
Copy link
Author

lgtout commented Jan 31, 2021

Just did some more investigating. I see that the exception gets caught by the try-catch.
It is kotlinx.coroutines.JobCancellationException: Parent job is Cancelling; job=StandaloneCoroutine{Cancelling}@926b1ac
Then the app crashes.

@lgtout
Copy link
Author

lgtout commented Feb 5, 2021

I read your post about coroutine exceptions, which confirmed that the try-catch inside launch will catch calls to getAndroidVersions(), but will not catch calls to getAndroidVersionFeatures() because those take place within a non-top-level async.

Any exception thrown within the async is propagated to the root launch. And the only way to catch an exception propagated in this way is by installing a CoroutineExceptionHandler.

The following covers all exception cases:

fun performNetworkRequestsConcurrently() {
    uiState.value = UiState.Loading
    viewModelScope.launch(CoroutineExceptionHandler {
        _, throwable ->
        Timber.v(throwable)
        uiState.value = UiState.Error("Network Request failed")
    }) {
        try {
            val recentVersions = mockApi.getRecentAndroidVersions()
            val versionFeaturesJobs = recentVersions.map {
                androidVersion ->
                async {
                    mockApi.getAndroidVersionFeatures(
                            androidVersion.apiLevel
                    )
                }
            }
            val versionFeatures = versionFeaturesJobs.awaitAll()
            uiState.value = UiState.Success(versionFeatures)
        } catch (exception: Exception) {
            uiState.value = UiState.Error("Network Request failed")
        }
    }
}

illarionov added a commit to illarionov/Kotlin-Coroutine-Use-Cases-on-Android that referenced this issue Sep 23, 2021
@kaal-dam
Copy link

Hello @LukasLechnerDev it seems that the issue described here is still present in the current version of the course

Using async directly rather than viewModelScope.async result in crash when the api response is in error

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants