Что такое Coroutine Builders в Kotlin
Что проверяют
Понимаете ли вы, откуда в приложении берётся корутина и кто отвечает за её жизнь. За вопросом стоит структурированная многозадачность: билдер всегда запускается в скоупе, скоуп привязан к экрану или к модели, отмена скоупа гасит всё дерево. В Android это прямая причина падений и утечек на закрытом экране.
Как отвечать
Билдер это функция, которая создаёт корутину и связывает её с родителем. Основных три:
launchвозвращаетJob, результат не нужен, исключение сразу уходит вверх по дереву и валит скоуп, если его не поймалCoroutineExceptionHandler;asyncвозвращаетDeferred, исключение запоминается и вылетает наawait, но родителя он всё равно отменяет, если это не корень скоупа сSupervisorJob;runBlockingблокирует текущий поток и служит мостом из обычного кода, то есть уместен в тестах и в точке входа, а не в коде экрана.
Рядом стоят coroutineScope и supervisorScope: это не билдеры, а suspend-функции, которые ждут всех детей и различаются тем, отменяет ли падение одного ребёнка остальных.
viewModelScope.launch {
val user = async { repo.user() }
val feed = async { repo.feed() }
render(user.await(), feed.await())
}Где спотыкаются
Запускают всё от GlobalScope. Такая корутина не привязана ни к чему, переживает экран и держит ссылки на него. В Android берут viewModelScope или lifecycleScope, тогда уход с экрана отменяет работу сам.
Пишут async { ... }.await() подряд и считают, что получили параллельность. Пока задачи не запущены обе до первого ожидания, это обычный последовательный код с лишней обёрткой.
Путают билдер и переключение контекста. withContext ничего не запускает, он меняет диспетчер внутри уже идущей корутины: ради похода в базу новая корутина не нужна, достаточно сменить контекст.