```supervisorScope { async { throw Exc...
# coroutines
m
Copy code
supervisorScope {
    async {
        throw Exception()
    }

    async {
        throw Exception()    
    }
}
^ app doesn't crash
Copy code
supervisorScope {
    launch {
        throw Exception()
    }

    launch {
        throw Exception()    
    }
}
^ app crashes what am I doing wrong?
m
When
async
has a
SupervisorJob
as a parent (which is in that case), it won’t crash until you call
.await()
.
launch
automatically throws the exceptions as soon as it happens but that’s not the case of
async
. It’ll hold it until you call
await
Notice, that if you change
supervisorScope
for
coroutineScope
, now the parent
Job
of async is of type
Job
(not
SupervisorJob
) and the exception will be propagated as soon as it happens
That’s because a
SupervisorJob
let’s the coroutine handle the exception (and crash if it hasn’t been handled)
An article about this is planned to be published next Wednesday; based on Florina Muntenescu and my talk at KotlinConf
👍 3
m
@Manuel Vivo could you hep me woth this one?
Copy code
override fun onChanged(t: AccountInfo) {
        fetchDataAfterAccountInfo?.cancel()
        fetchDataAfterAccountInfo = viewModelScope.launch {
            try {
                supervisorScope {
                    launch {
                        val purchases = appService.fetchPurchasesWithPickupData().purchases
                        pickPurchasesLiveData.postValue(purchases)
                    }
                    launch {
                        val paymentPlan = appService.fetchPaymentPlan()
                        paymentPlanLiveData.postValue(paymentPlan.instalments)
                    }
                }
            } catch (e : Exception) {
                Timber.e(e, "loading data after accountInfo failed")
            }
        }
    }
m
supervisorScope
is not going to propagate the exception up to the try/catch, if you want that behavior, use
coroutineScope
m
everytime after a new accountInfo, I want to load 2 different set if data and put them into livedata if one fails, it should NOT influence the other one but I want to be able to cancel both at same time
how would you code?
m
Then use
supervisorScope
but try/catch the inner launches instead of try/catching the
supervisorScope
call
m
Copy code
override fun onChanged(info: AccountInfo) {
        fetchDataAfterAccountInfo?.cancel()
        fetchDataAfterAccountInfo = viewModelScope.launch(CoroutineExceptionHandler { _, e -> Timber.e(e, "loading data after accountInfo failed") }) {
            supervisorScope {
                launch {
                    val purchases = appService.fetchPurchasesWithPickupData().purchases
                    pickPurchasesLiveData.postValue(purchases)
                }
                launch {
                    val paymentPlan = appService.fetchPaymentPlan()
                    paymentPlanLiveData.postValue(paymentPlan.instalments)
                }
            }
        }
    }
this should do it right?! 😅
It’s the point of the section. You should never do that
because it’s pointless, it’s not doing anything
m
why does the method has this argument then?
e
The argument is more for changing the coroutine dispatcher so you can run in a different thread pool, for instance. The proper way to deal with the SupervisorJob would be to define
job
as
CoroutineScope(SupervisorJob())
and then perform multiple
launch {}
invocations off of that so they can still run independently.
I think you can also add a CoroutineExceptionHandler but I could be wrong