Можно ли оборачивать вызовы корутинных билдров в try-catch и как обрабатываются исключения в Kotlin
Что проверяют
Понимаете ли вы, что try-catch вокруг вызова launch ничего не поймает, и знаете ли, куда исключение уходит при структурированной конкурентности. Следом обычно спрашивают про разницу между launch и async и про то, почему CancellationException нельзя гасить.
Как отвечать
Обернуть вызов билдера можно, но пользы не будет: launch возвращает управление сразу, а тело выполняется позже и обычно в другом потоке. Внешний try-catch поймает разве что ошибку создания корутины. Ловить нужно внутри корутины, вокруг подозрительного вызова.
Дальше механика:
launch: непойманное исключение считается необработанным. Оно отменяет родительскийJobи всех братьев, потом попадает вCoroutineExceptionHandlerкорня, а если его нет, то в обработчик потока, то есть в краш;async: исключение сохраняется вDeferredи бросается наawait(), но родителя такая корутина всё равно отменяет, если скоуп не супервизорный.CoroutineExceptionHandlerдляasyncне работает;withContextиcoroutineScope: обычные suspend-функции, они пробрасывают исключение вызывающему коду, иtry-catchвокруг них работает как в синхронном коде;supervisorScopeиSupervisorJob: падение одного ребёнка не роняет остальных, каждый сам разбирается со своей ошибкой.
CoroutineExceptionHandler ставится в контекст скоупа или корневой корутины, во вложенном launch он игнорируется. Это сеть последнего рубежа для логирования, а не замена локальной обработке.
Отдельно про отмену: CancellationException это штатный сигнал завершения, а catch (e: Exception) и runCatching проглатывают его и ломают отмену. Ловите конкретные типы или пробрасывайте его дальше: catch (e: CancellationException) { throw e }.
Где спотыкаются
Оборачивают scope.launch { } снаружи и считают, что защитились. В логах потом падение всего скоупа вместе с соседними задачами.
Ставят CoroutineExceptionHandler на дочернюю корутину и удивляются молчанию. Обработчик учитывается только у корня иерархии.
Ловят Exception вокруг сетевого вызова и вместе с ошибкой сети гасят отмену. Экран уже закрыт, а корутина продолжает работать и писать в мёртвую ViewModel.