Что такое контекст корутины
Что проверяют
Знаете ли вы, из чего состоит CoroutineContext и как он наследуется. Это проверка на понимание структурной конкурентности: от контекста зависит, где выполнится код, кто его отменит и куда уйдёт необработанное исключение. Для Android это напрямую про утечки и падения после закрытия экрана.
Как отвечать
Контекст это неизменяемый набор элементов, у каждого свой ключ, складываются они оператором плюс. Назовите четыре: Job отвечает за жизненный цикл и отмену, CoroutineDispatcher за поток или пул, CoroutineName за имя в логах, CoroutineExceptionHandler за необработанные исключения.
Правило наследования важнее списка: дочерняя корутина берёт контекст родителя, но её Job всегда новый и подчинён родительскому. Поэтому отмена родителя отменяет детей, а передача в билдер собственного Job() эту связь рвёт.
viewModelScope.launch(Dispatchers.IO + CoroutineName("sync")) {
val data = repo.load() // фоновый диспетчер
withContext(Dispatchers.Main) { render(data) }
}Диспетчер выбирают по типу работы: Main для интерфейса, IO для сети и диска, Default для счёта. Область берут готовую, привязанную к жизненному циклу, чтобы отмена приходила сама. Отдельно стоит упомянуть withContext: он не заводит новую область, а на время блока подменяет элементы контекста, чаще всего диспетчер, сохраняя подчинение по отмене.
Где спотыкаются
Передают в билдер новый Job и потом удивляются, что отмена области ничего не отменяет, а исключение ребёнка не доходит до родителя.
Вешают CoroutineExceptionHandler на async и ждут срабатывания. У async исключение хранится в Deferred и выстреливает на await, обработчик имеет смысл только в корневой корутине launch.
Считают Dispatchers.IO способом ускорить вычисления. Он рассчитан на ожидание ввода-вывода и разрешает держать много потоков сразу, а тяжёлый счёт там отбирает потоки у настоящих блокирующих операций. Для счёта есть Default.