Что такое CoroutineExceptionHandler
Что проверяют
Понимаете ли вы, что это обработчик последней инстанции, и знаете ли, где он не сработает.
Как отвечать
Это элемент контекста корутины, получающий необработанные исключения. Аналог обработчика непойманных исключений для потока: последний рубеж перед тем, как приложение упадёт.
val handler = CoroutineExceptionHandler { _, e ->
Log.e("app", "необработанная ошибка", e)
}
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main + handler)Ограничения, из-за которых он часто не срабатывает и кажется сломанным:
1. Работает только на корневой корутине области. Переданный в дочерний запуск, он будет проигнорирован: исключение поднимается вверх по иерархии, и обрабатывает его тот обработчик, что установлен у корня. Это самая частая причина недоумения.
2. Не работает для отложенного результата. Там исключение сохраняется и выбрасывается при получении значения, поэтому ловить его надо в блоке перехвата вокруг ожидания. Исключение считается обработанным по определению, и до обработчика оно не дойдёт.
3. Не ловит отмену. Исключение отмены это штатный сигнал, а не ошибка, и оно намеренно игнорируется.
4. Не позволяет продолжить работу. К моменту вызова корутина уже завершена, восстановить её нельзя. Это место для журналирования и оповещения, а не для восстановления.
Отсюда практическое правило: локальные ошибки обрабатываются перехватом прямо в корутине, а обработчик контекста нужен для того, что вы не предусмотрели, чтобы это не роняло приложение молча.
Взаимодействие с надзорным заданием стоит упомянуть отдельно: без него сбой одной дочерней корутины отменяет всех соседей, и обработчик получит ошибку уже после того, как область развалилась. Поэтому в областях экрана их используют вместе.
Где спотыкаются
Вешают обработчик на дочернюю корутину и удивляются, что он молчит.
Ждут, что он поймает ошибку отложенного результата.
Глотают в нём отмену и ломают завершение работы.
Рассчитывают восстановить выполнение корутины изнутри обработчика.