launch — суть, fire-and-forget запуск корутин і як працює

Автор: IT Sectr Опубліковано: 2026-06-22 Час читання: 7 хв

launch — Coroutine Builder у Kotlin, який запускає корутину без повернення результату, повертаючи об'єкт Job для керування виконанням. Цей білдер реалізує патерн fire-and-forget: корутина починає роботу у фоновому потоці й автоматично завершується. За даними документації JetBrains, 2024, launch є основним способом запуску паралельних завдань у Kotlin Coroutines.

Головне

  • launch — білдер для запуску корутин без повернення результату (fire-and-forget)
  • Job — об'єкт керування корутиною з методами cancel(), join(), isActive
  • launch інтегрується з CoroutineScope для автоматичного скасування дочірніх корутин
  • CoroutineStart.LAZY дозволяє відкласти запуск до явного виклику start() або join()
  • launch в Android використовується для збереження в БД, мережевих викликів та оновлення UI

Що таке launch у Kotlin Coroutines?

launch — це функція-розширення Kotlin, доступна через імпорт kotlinx.coroutines, яка створює нову корутину в заданому CoroutineScope. На відміну від звичайних функцій, код всередині launch виконується конкурентно — корутина може призупинятися (suspend) без блокування потоку та відновлюватися пізніше.

Білдер launch є фундаментальним будівельним блоком корутинної моделі Kotlin. Він не повертає обчислене значення, але повертає об'єкт Job, який дозволяє контролювати виконання корутини. Усі дочірні корутини, запущені через launch всередині іншої корутини, прив'язуються до батьківської.

Синтаксис і параметри launch

Білдер launch визначається як inline-функція з кількома параметрами: CoroutineScope, CoroutineContext, CoroutineStart і suspend-блок. Параметри мають значення за замовчуванням, що робить launch зручним для типових сценаріїв.

kotlin
public fun CoroutineScope.launch(
    context: CoroutineContext = EmptyCoroutineContext,
    start: CoroutineStart = CoroutineStart.DEFAULT,
    block: suspend CoroutineScope.() -> Unit
): Job

Параметр context приймає CoroutineContext, який об'єднує диспетчер, обробник винятків та іменований елемент. Найчастіше передається Dispatchers.IO, Dispatchers.Main або SupervisorJob для ізоляції помилок.

Job і керування життєвим циклом

Job — повернений об'єкт, який представляє життєвий цикл корутини. Job може перебувати в станах: New, Active, Completing, Completed, Cancelling, Cancelled. Кожен стан відображає статус виконання та дозволяє реагувати на зміни.

kotlin
val job = CoroutineScope(Dispatchers.IO).launch {
    repeat(10) { i ->
        delay(1000L)
        println("Прогрес: $i")
    }
}

println("Job активний: ${job.isActive}")
delay(2500L)
job.cancel()
println("Job скасовано: ${job.isCancelled}")

Job підтримує ієрархію: якщо батьківська корутина скасовується, усі дочірні автоматично скасовуються. SupervisorJob змінює цю поведінку — дочірні корутини не скасовуються при помилці однієї з них.

Структурована конкурентність у launch

Структурована конкурентність означає, що кожна корутина запускається в певному CoroutineScope, і scope не завершиться, доки всі дочірні корутини не закінчать роботу. launch повністю підтримує цей принцип — корутини, запущені всередині іншої корутини, є її дочірніми.

Вкладені launch виклики

При вкладеному запуску launch утворюється дерево корутин. Батьківська корутина очікує завершення всіх дочірніх, що гарантує передбачуваний порядок виконання та спрощує керування ресурсами.

kotlin
fun main() = runBlocking {
    launch {
        launch {
            delay(1000L)
            println("Дочірній 1 завершено")
        }
        launch {
            delay(500L)
            println("Дочірній 2 завершено")
        }
        println("Усі дочірні завершуються до цього рядка")
    }
}

Ця поведінка відрізняється від thread-based конкурентності, де дочірні потоки не прив'язані до батьківського. У корутинах батько не завершується, доки всі діти не закінчать роботу.

Обробка винятків у launch

Обробка винятків у launch залежить від типу Job. Для звичайного Job винятки поширюються на батьківську корутину та скасовують її. Для SupervisorJob або SupervisorScope винятки ізолюються — помилка однієї дочірньої корутини не впливає на інші.

kotlin
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
    try {
        riskyOperation()
    } catch (e: Exception) {
        println("Перехоплено: ${e.message}")
    }
}
scope.launch {
    println("Це все ще працює завдяки SupervisorJob")
}

Для глобальної обробки невідловлених винятків використовується CoroutineExceptionHandler. Він перехоплює винятки, які не були оброблені всередині корутини, і дозволяє залогіювати помилку без крашу застосунку.

Приклади використання launch в Android

В Android launch застосовується повсюдно: від ViewModel до WorkManager. Основний патерн — використання lifecycleScope у Fragment та viewModelScope у ViewModel для автоматичного скасування корутин при завершенні життєвого циклу компонента.

kotlin
class ProfileViewModel : ViewModel() {
    private val repository = UserRepository()

    fun loadProfile(userId: String) {
        viewModelScope.launch(Dispatchers.IO) {
            val profile = repository.fetchProfile(userId)
            withContext(Dispatchers.Main) {
                _profileState.update { it.copy(profile = profile) }
            }
        }
    }
}

viewModelScope автоматично скасовує корутини при знищенні ViewModel. Це виключає витоки та гарантує, що фонові операції не продовжуються після втрати контексту. Додатково можна використовувати withContext для перемикання між диспетчерами.

Часті запитання

Чим відрізняється launch від async у Kotlin Coroutines?

launch повертає Job і не повертає результат виконання, а async повертає Deferred<T> для отримання результату. launch використовується для fire-and-forget операцій, async — коли потрібно дочекатися та використати повернене значення.

Як скасувати корутину, запущену через launch?

Викличте job.cancel() на збереженому об'єкті Job. Для групового скасування скасуйте весь CoroutineScope через scope.cancel(). Корутина має бути кооперативною — перевіряти isActive або використовувати перевірювані suspend-функції.

Що робити, якщо launch викинув виняток?

Використовуйте try-catch всередині launch блоку або передайте CoroutineExceptionHandler у CoroutineContext. Для ізоляції помилок використовуйте SupervisorJob — тоді виняток в одній дочірній корутині не скасує інші.

Чи можна запустити launch без CoroutineScope?

Ні, launch — функція-розширення CoroutineScope. Без scope корутина не зможе слідувати принципу структурованої конкурентності. Використовуйте GlobalScope.launch з обережністю — це створює корутину без прив'язки до життєвого циклу.

Скільки launch корутин можна запустити одночасно?

Кількість обмежена пулом потоків диспетчера. Dispatchers.Default використовує кількість потоків, рівну числу ядер CPU. Dispatchers.IO підтримує до 64 потоків. При запуску більшої кількості корутин вони стають у чергу.

Підсумки

  • launch — основний білдер для fire-and-forget корутин, що повертає об'єкт Job
  • Job надає методи керування: cancel(), join(), isActive, isCancelled, isCompleted
  • Структурована конкурентність гарантує скасування дочірніх корутин при скасуванні батьківської
  • Обробка винятків залежить від типу Job: звичайний поширює помилки, SupervisorJob ізолює
  • lifecycleScope та viewModelScope — готові рішення для запуску launch в Android
  • CoroutineStart.LAZY відкладає запуск до явного виклику start() або join()
  • launch в Android застосовується для мережевих запитів, запису в БД, аналітики та кешування

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також