Что такое корутины?

Корутины (coroutines) в Kotlin — это легковесные потоки, которые позволяют выполнять асинхронный и неблокирующий код в простом синтаксисе, похожем на синхронный. Они разработаны для эффективной работы с задачами, которые могут приостанавливаться и возобновляться без блокировки потоков.

Корутины — это одна из ключевых фич Kotlin и основа современного Android-разработки.

🔍 Зачем нужны корутины

Традиционный подход к асинхронному программированию (через Thread, AsyncTask, Callback, ExecutorService) имеет много недостатков:

  • сложность в управлении потоками,

  • callback hell,

  • утечки памяти,

  • плохая читаемость кода.

Корутины позволяют:

  • упростить асинхронный код;

  • не блокировать основной поток;

  • обрабатывать ошибки через try-catch;

  • управлять жизненным циклом через Job, Scope и Dispatcher.

🔹 Основные понятия

1. suspend функции

Это функции, которые могут быть приостановлены и возобновлены корутиной.

suspend fun fetchData(): String {
delay(1000) // не блокирует поток
return "result"
}

delay() — приостанавливает выполнение корутины, но не блокирует поток (в отличие от Thread.sleep()).

2. Запуск корутины: launch и async

GlobalScope.launch {
// фоновая задача
}
GlobalScope.async {
// фоновая задача с возвращаемым значением
}
  • launch — не возвращает результат, используется для «огневых» задач.

  • async — возвращает Deferred<T>, из которого можно получить результат через .await().

3. CoroutineScope

Это область действия, внутри которой живут корутины. Она управляет временем жизни и отменой.

val scope = CoroutineScope(Dispatchers.IO)
scope.launch {
// работает в пуле фоновых потоков
}

4. Dispatchers

Определяют, на каком потоке или пуле потоков выполняется корутина.

  • Dispatchers.Main — главный UI-поток.

  • Dispatchers.IO — для операций ввода-вывода (файлы, сети, БД).

  • Dispatchers.Default — для тяжёлых вычислений.

  • Dispatchers.Unconfined — запускается в текущем потоке, но может переключиться.

5. Job и отмена

Каждая корутина создаёт Job, которым можно управлять:

val job = scope.launch {
...
}
job.cancel() // отменяет выполнение

🔁 Пример корутины с launch

fun main() = runBlocking {
launch {
delay(1000)
println("Hello from coroutine!")
}
println("Main thread continues")
}

Вывод:

Main thread continues
Hello from coroutine!

→ runBlocking запускает корутину в блокирующем режиме, чтобы пример работал в main().

⚠️ Отличие от потоков

Параметр Корутины Потоки (Thread)
Легковесность ✅ Да ❌ Нет (тяжёлые)
--- --- ---
Кол-во в JVM Миллионы Тысячи
--- --- ---
Переключение Быстрое, без контекста Медленное, с контекстом
--- --- ---
Поддержка отмены ✅ Да (через Job) ❌ Нет по умолчанию
--- --- ---
API Высокоуровневое Низкоуровневое
--- --- ---

Применение в Android

  • Загрузка данных с сервера (через Retrofit + coroutines).

  • Работа с базами данных (Room поддерживает suspend-функции).

  • Асинхронные операции в ViewModel (через viewModelScope).

  • Использование Flow для реактивного стриминга данных.

📦 Библиотеки и интеграции

  • kotlinx.coroutines — официальная библиотека от JetBrains.

  • Поддержка в Android Jetpack: ViewModel, LiveData, Room, WorkManager.

  • Поддержка в Retrofit, ktor, SQLDelight и др.

🧠 Итого

Корутины — это эффективный инструмент для асинхронного программирования в Kotlin. Они позволяют писать понятный, читабельный и не блокирующий код, использовать suspend функции, работать с потоками через Dispatchers, и при этом избегать громоздкой синхронизации и колбэков. Они легковесны, отменяемы и легко масштабируются — именно поэтому они стали стандартом в Android-разработке.