> Что такое Kotlin Coroutines (Kotlin, Android)

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

Компании: SimbirSoft, MTS, Бел Интегратор, Юрент, ЛеруаМерлен, Одноклассники, TrendTech, Яндекс

Стек: Kotlin, Android

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

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

Kotlin Coroutines - это механизм для асинхронного и конкурентного программирования в Kotlin, основанный на концепции легковесных потоков. Они позволяют приостанавливать выполнение функции без блокировки потока, что делает код более читаемым и эффективным по сравнению с callbacks или RxJava. Coroutines строятся поверх обычных потоков и управляются через диспетчеры, обеспечивая структурированный подход к параллельным задачам.

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

Coroutines - это не потоки, а скорее конечные автоматы, которые могут приостанавливаться и возобновляться. Ключевое отличие от потоков: приостановка coroutine не блокирует поток, на котором она выполняется. Это позволяет запускать тысячи coroutines на одном потоке без деградации производительности.

Основные компоненты:

  • CoroutineScope - определяет жизненный цикл coroutines (например, viewModelScope, lifecycleScope).
  • CoroutineContext - набор параметров: Job, Dispatcher, CoroutineExceptionHandler.
  • Dispatcher - управляет тем, на каком пуле потоков выполняется coroutine (Dispatchers.Main, Dispatchers.IO, Dispatchers.Default).
  • Suspend functions - функции, которые можно приостанавливать и возобновлять, не блокируя поток.

Механизм работы: при вызове suspend-функции компилятор преобразует её в state machine. При приостановке состояние сохраняется, а при возобновлении - восстанавливается. Это позволяет писать асинхронный код в императивном стиле без вложенных callbacks.

На практике

В Android coroutines используются для:

  • Выполнения сетевых запросов и работы с БД без блокировки UI-потока.
  • Отмены фоновых задач при уничтожении Activity/Fragment (через viewModelScope).
  • Параллельного выполнения независимых задач с помощью async/await.
  • Последовательного выполнения задач с обработкой ошибок через try/catch или CoroutineExceptionHandler.

Основные паттерны:

  • launch - запуск coroutine без возврата результата.
  • async - запуск с возвратом результата через Deferred.
  • withContext - переключение диспетчера внутри coroutine.
  • delay - неблокирующая задержка (аналог Thread.sleep, но без блокировки).

Пример кода

// Простой пример: загрузка данных с сети
fun loadUserData() {
    viewModelScope.launch {
        try {
            val user = withContext(Dispatchers.IO) {
                api.fetchUser() // suspend-функция
            }
            _userLiveData.value = user
        } catch (e: Exception) {
            _errorLiveData.value = e.message
        }
    }
}

// Параллельное выполнение
viewModelScope.launch {
    val user = async { api.fetchUser() }
    val posts = async { api.fetchPosts() }
    val result = Pair(user.await(), posts.await())
}

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

Начни с определения: coroutines - это инструмент для асинхронного программирования, который позволяет писать последовательный код без блокировки потоков. Затем объясни разницу между coroutine и потоком: поток - тяжёлый, блокируемый, а coroutine - лёгкая, приостанавливаемая. Упомяни ключевые компоненты: scope, context, dispatcher. Приведи пример использования в Android: viewModelScope.launch для сетевого запроса. Если спросят про отмену - объясни, что Job позволяет отменять coroutine, и это автоматически происходит при очистке scope.

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

Интервьюер оценивает:

  • Понимание базовой концепции приостановки и возобновления.
  • Знание отличий от потоков и callbacks.
  • Умение работать с диспетчерами и выбирать правильный для задачи.
  • Понимание структурированной конкурентности (structured concurrency) и отмены.
  • Практический опыт: как использовать в Android-компонентах.

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

  • Путаница между coroutine и потоком: утверждение, что coroutine - это поток.
  • Незнание, что delay не блокирует поток, в отличие от Thread.sleep.
  • Использование GlobalScope вместо привязанного к жизненному циклу scope - приводит к утечкам памяти.
  • Запуск тяжёлых операций на Dispatchers.Main без withContext.
  • Игнорирование отмены: не проверка isActive в длительных циклах.
  • Неправильная обработка исключений: launch не пробрасывает исключения наружу, их нужно ловить внутри.

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

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