Skip to content

Commit 4e6195c

Browse files
Adapt UseCase#13 - "Exception Handling"
1 parent 901040c commit 4e6195c

File tree

3 files changed

+17
-52
lines changed

3 files changed

+17
-52
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ The factorial calculation here is not performed by a single coroutine, but by an
168168
### 13. Exception Handling
169169

170170
This use case demonstrates different ways of handling exceptions using `try/catch` and `CoroutineExceptionHandler`. It also demonstrates when you should to use `supervisorScope{}`: In situations when you don't want a failing coroutine to cancel
171-
its sibling coroutines. In the use case the results of the successful responses are shown even tough one response wasn't successful.
171+
its sibling coroutines. In one implementation of this use case, the results of the successful responses are shown even tough one response wasn't successful.
172172

173173
[[code](app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/usecases/coroutines/usecase13/ExceptionHandlingViewModel.kt)]
174174

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/usecases/coroutines/usecase13/ExceptionHandlingActivity.kt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,6 @@ class ExceptionHandlingActivity : BaseActivity() {
4242
binding.btnShowResultsEvenIfChildCoroutineFailsTryCatch.setOnClickListener {
4343
viewModel.showResultsEvenIfChildCoroutineFails()
4444
}
45-
binding.btnShowResultsEvenIfChildCoroutineFailsRunCatching.setOnClickListener {
46-
viewModel.showResultsEvenIfChildCoroutineFailsRunCatching()
47-
}
4845
}
4946

5047
private fun render(uiState: UiState) {
@@ -97,13 +94,11 @@ class ExceptionHandlingActivity : BaseActivity() {
9794
btnExceptionTryCatch.isEnabled = true
9895
btnCoroutineExceptionHandler.isEnabled = true
9996
btnShowResultsEvenIfChildCoroutineFailsTryCatch.isEnabled = true
100-
btnShowResultsEvenIfChildCoroutineFailsRunCatching.isEnabled = true
10197
}
10298

10399
private fun disableButtons() = with(binding) {
104100
btnExceptionTryCatch.isEnabled = false
105101
btnCoroutineExceptionHandler.isEnabled = false
106102
btnShowResultsEvenIfChildCoroutineFailsTryCatch.isEnabled = false
107-
btnShowResultsEvenIfChildCoroutineFailsRunCatching.isEnabled = false
108103
}
109104
}

app/src/main/java/com/lukaslechner/coroutineusecasesonandroid/usecases/coroutines/usecase13/ExceptionHandlingViewModel.kt

Lines changed: 16 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,7 @@ package com.lukaslechner.coroutineusecasesonandroid.usecases.coroutines.usecase1
33
import androidx.lifecycle.viewModelScope
44
import com.lukaslechner.coroutineusecasesonandroid.base.BaseViewModel
55
import com.lukaslechner.coroutineusecasesonandroid.mock.MockApi
6-
import kotlinx.coroutines.CoroutineExceptionHandler
7-
import kotlinx.coroutines.async
8-
import kotlinx.coroutines.launch
9-
import kotlinx.coroutines.supervisorScope
6+
import kotlinx.coroutines.*
107
import timber.log.Timber
118

129
class ExceptionHandlingViewModel(
@@ -37,41 +34,6 @@ class ExceptionHandlingViewModel(
3734
}
3835

3936
fun showResultsEvenIfChildCoroutineFails() {
40-
uiState.value = UiState.Loading
41-
viewModelScope.launch {
42-
43-
supervisorScope {
44-
val oreoFeaturesDeferred = async { api.getAndroidVersionFeatures(27) }
45-
val pieFeaturesDeferred = async { api.getAndroidVersionFeatures(28) }
46-
val android10FeaturesDeferred = async { api.getAndroidVersionFeatures(29) }
47-
48-
val oreoFeatures = try {
49-
oreoFeaturesDeferred.await()
50-
} catch (e: Exception) {
51-
Timber.e("Error loading oreo features")
52-
null
53-
}
54-
55-
val pieFeatures = try {
56-
pieFeaturesDeferred.await()
57-
} catch (e: Exception) {
58-
Timber.e("Error loading pie features")
59-
null
60-
}
61-
62-
val android10Features = try {
63-
android10FeaturesDeferred.await()
64-
} catch (e: Exception) {
65-
Timber.e("Error loading oreo features")
66-
null
67-
}
68-
val versionFeatures = listOfNotNull(oreoFeatures, pieFeatures, android10Features)
69-
uiState.value = UiState.Success(versionFeatures)
70-
}
71-
}
72-
}
73-
74-
fun showResultsEvenIfChildCoroutineFailsRunCatching() {
7537
uiState.value = UiState.Loading
7638
viewModelScope.launch {
7739

@@ -84,14 +46,22 @@ class ExceptionHandlingViewModel(
8446
oreoFeaturesDeferred,
8547
pieFeaturesDeferred,
8648
android10FeaturesDeferred
87-
).mapNotNull { deferred ->
88-
runCatching {
89-
deferred.await()
90-
}.onFailure {
91-
Timber.e("Failure loading features of an Android Version")
92-
}.getOrNull()
49+
).mapNotNull {
50+
try {
51+
it.await()
52+
} catch (exception: Exception) {
53+
// We have to re-throw cancellation exceptions so that
54+
// our Coroutine gets cancelled immediately.
55+
// Otherwise, the CancellationException is ignored
56+
// and the Coroutine keeps running until it reaches the next
57+
// suspension point.
58+
if (exception is CancellationException) {
59+
throw exception
60+
}
61+
Timber.e("Error loading feature data!")
62+
null
63+
}
9364
}
94-
9565
uiState.value = UiState.Success(versionFeatures)
9666
}
9767
}

0 commit comments

Comments
 (0)