> Что такое Coroutine Builders в Kotlin (Kotlin, Android)

Уровень: junior · Роль: mobile · Категория: Технические вопросы

Компании: PayMe

Стек: Kotlin, Android

> Пример ответа

Короткий ответ

Coroutine Builders - это функции, которые запускают корутину, то есть создают новую корутину и ставят её в очередь на выполнение в рамках заданного CoroutineContext. Основные билдеры в Kotlin: launch, async, runBlocking. Они отличаются способом возврата результата и поведением в отношении исключений. launch возвращает Job и не возвращает результат, async возвращает Deferred (future-подобный объект), runBlocking блокирует текущий поток до завершения корутины.

Подробное объяснение

Coroutine Builders - это entry point для корутин. Без них корутина не может быть запущена. Каждый билдер принимает CoroutineContext (опционально), CoroutineStart (опционально) и блок кода с suspend-функциями.

Три основных билдера:

  1. launch - запускает корутину, которая не возвращает результат. Возвращает Job, который можно использовать для отмены или ожидания завершения. Исключения внутри launch пробрасываются в родительский контекст (если не перехвачены).

  2. async - запускает корутину, которая возвращает результат через Deferred<T>. Deferred - это аналог Future в Java, но с поддержкой suspension. Результат получается через await(). Исключения внутри async не пробрасываются сразу, а сохраняются в Deferred и выбрасываются при вызове await().

  3. runBlocking - блокирует текущий поток до завершения корутины. Используется в основном в main-функции или в тестах, где нужно дождаться завершения корутины. В production-коде Android его следует избегать, так как он блокирует UI-поток.

Есть также coroutineScope и supervisorScope, но они не являются билдерами в строгом смысле - это scope-функции, которые создают новую область видимости для дочерних корутин.

На практике

В Android-разработке чаще всего используется launch для запуска фоновых задач (сетевые запросы, работа с БД) и async для параллельного выполнения нескольких задач, когда нужен результат. runBlocking применяется в тестах и в main-функции для демонстрации.

Важно помнить, что билдеры должны вызываться внутри CoroutineScope. На Android это обычно lifecycleScope (для Activity/Fragment) или viewModelScope (для ViewModel). Использование глобального GlobalScope считается антипаттерном, так как корутина не будет автоматически отменена при уничтожении компонента.

Пример кода

// launch - запуск без результата
lifecycleScope.launch {
    val result = repository.fetchData()
    updateUI(result)
}

// async - запуск с результатом
lifecycleScope.launch {
    val deferred1 = async { repository.fetchUser() }
    val deferred2 = async { repository.fetchPosts() }
    val user = deferred1.await()
    val posts = deferred2.await()
    showData(user, posts)
}

// runBlocking - блокирующий запуск (только для тестов или main)
fun main() = runBlocking {
    val result = async { fetchFromNetwork() }.await()
    println(result)
}

Как отвечать на собеседовании

Начни с краткого определения, затем перечисли основные билдеры и их отличия. Обязательно упомяни, что launch не возвращает результат, а async возвращает Deferred. Добавь пример использования в Android-контексте: lifecycleScope.launch для фоновой задачи, async для параллельных запросов. Если спросят про runBlocking, скажи, что он блокирует поток и используется только в тестах или в main. Не углубляйся в детали реализации, если не просят.

Что проверяет интервьюер

Интервьюер проверяет:

  • понимание базовых концепций корутин (suspension, CoroutineScope, CoroutineContext);
  • знание различий между launch и async;
  • понимание, когда какой билдер использовать;
  • знание Android-специфики: lifecycleScope, viewModelScope, избегание GlobalScope;
  • понимание поведения исключений в разных билдерах.

Типичные ошибки

  • Использование runBlocking в UI-потоке Android - это блокирует интерфейс и вызывает ANR.
  • Использование GlobalScope без необходимости - корутина не отменяется при уничтожении компонента.
  • Вызов async без await() - корутина запустится, но результат не будет использован, и исключение может быть потеряно.
  • Запуск билдера вне CoroutineScope - компилятор выдаст ошибку, но новички часто пытаются вызвать launch напрямую из функции без scope.
  • Путаница между launch и async при необходимости получить результат - launch не возвращает значение, только Job.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью