usecase4/VariableAmountOfNetworkRequestsViewModel#performNetworkRequestsConcurrently crashes on exception
lgtout opened this issue · comments
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
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.
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")
}
}
}
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