Coroutine Builder — funkce Kotlin Coroutines, které vytvářejí a spouštějí korutiny a určují způsob jejich provádění. Buildery launch, async, runBlocking a produce pokrývají různé scénáře: od úloh na pozadí až po paralelní výpočty s vrácením výsledku. Podle údajů JetBrains, 2024 je Coroutine Builder základem modelu korutin a zajišťuje strukturovanou souběžnost a správu životního cyklu.
Hlavní body
Coroutine Builder — je rozšiřující funkce Kotlinu, která přijímá CoroutineScope a suspend-blok, vytváří a spouští novou korutinu. Každý builder určuje, jak bude korutina provedena: s výsledkem nebo bez, s blokováním vlákna nebo asynchronně. Buildery jsou vstupními body do modelu korutin jazyka.
Všechny buildery pracují přes CoroutineScope, který spravuje životní cyklus podřízených korutin. Při zrušení scope jsou všechny korutiny spuštěné přes něj automaticky zrušeny — to je princip strukturované souběžnosti. Tento přístup zabraňuje únikům korutin a zaručuje předvídatelné dokončení.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Buildery pracují uvnitř CoroutineScope
val job = launch {
delay(1000L)
println("Světe!")
}
println("Ahoj,")
job.join()
}
Kotlin poskytuje čtyři vestavěné buildery korutin: launch, async, runBlocking a produce. Každý má svůj návratový typ a oblast použití. Pro mobilní vývoj na Androidu jsou hlavními launch a async — pracují neblokujícím způsobem a integrují se s architektonickými komponentami.
| Builder | Návratový typ | Blokování vlákna | Scénář |
|---|---|---|---|
| launch | Job | Ne | Úlohy fire-and-forget |
| async | Deferred<T> | Ne | Paralelní výpočty |
| runBlocking | T | Ano | Testy, funkce main |
| produce | ReceiveChannel<E> | Ne | Streamový přenos (deprecated) |
Každý builder přijímá další parametry: CoroutineStart (strategie spuštění), CoroutineContext (dispečer, výjimky) a pojmenovaný blok kódu. Ve výchozím nastavení je korutina spuštěna okamžitě (CoroutineStart.DEFAULT).
launch — nejpoužívanější builder ve vývoji pro Android. Spouští korutinu, která nevrací výsledek, a vrací objekt Job pro správu jejího životního cyklu. Je to ideální volba pro operace, kde je potřeba pouze vedlejší efekt: uložení do databáze, odeslání analytiky, aktualizace UI.
Builder launch přijímá CoroutineScope, volitelný CoroutineContext a suspend-blok. Vrácený Job umožňuje zrušit korutinu, počkat na její dokončení nebo zkontrolovat stav.
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val job: Job = scope.launch(CoroutineStart.LAZY) {
val data = fetchFromNetwork()
saveToDatabase(data)
}
job.start()
job.join()
Parametr CoroutineStart.LAZY odkládá spuštění do explicitního volání start() nebo join(). To je užitečné pro odloženou inicializaci a podmíněné spouštění. Pro standardní okamžité spuštění se používá CoroutineStart.DEFAULT nebo je parametr vynechán.
async — builder vracející Deferred<T> — asynchronní příslib výsledku. Volání await() pozastaví korutinu do získání výsledku, aniž by blokovalo vlákno. To je hlavní mechanismus pro paralelní úlohy v korutinách Kotlinu.
async je zvláště efektivní, když je třeba provést několik nezávislých operací současně. Na rozdíl od sekvenčního volání suspend funkcí spouští async korutiny paralelně, čímž zkracuje celkovou dobu provádění.
suspend fun fetchUserData(): UserData {
val deferred1 = CoroutineScope(Dispatchers.IO).async { api.getProfile() }
val deferred2 = CoroutineScope(Dispatchers.IO).async { api.getSettings() }
val deferred3 = CoroutineScope(Dispatchers.IO).async { api.getNotifications() }
return UserData(
profile = deferred1.await(),
settings = deferred2.await(),
notifications = deferred3.await()
)
}
Deferred dědí z Job, takže async podporuje všechny operace životního cyklu: zrušení, čekání na dokončení, zpracování výjimek. Při zrušení scope jsou podřízené Deferred korutiny automaticky zrušeny.
runBlocking — jediný builder, který blokuje aktuální vlákno až do dokončení korutiny. Vytváří nový CoroutineScope a spouští předanou korutinu, přičemž blokuje volající vlákno. Používá se ve vstupních bodech main(), v testech a při integraci s blocking kódem.
runBlocking je opodstatněný ve třech scénářích: vstupní bod aplikace (main), jednotkové testy suspend funkcí a integrace s callback-based knihovnami, kde nelze použít suspend. V produkčním kódu Androidu je použití runBlocking na hlavním vlákně kategoricky nedoporučováno.
class CoroutineTest {
@Test
fun `test suspend function`() = runBlocking {
val result = mySuspendFunction()
assertEquals("expected", result)
}
}
Pro testy se doporučuje používat kotlinx-coroutines-test s TestCoroutineDispatcher místo runBlocking — to poskytuje kontrolu času a vyhýbá se blokování v testovacím prostředí.
Výběr Coroutine Builder závisí na vráceném výsledku a scénáři provádění. Pokud operace nevyžaduje vrácení dat — použijte launch. Pokud je potřeba výsledek asynchronní operace — async. runBlocking aplikujte pouze pro bridging a produce nahraďte Flow pro reaktivní streamy.
V Android projektech používajících Kotlin Coroutines je hlavním párem builderů launch a async. launch se používá ve ViewModel a UseCases pro spouštění korutin a async — pro paralelní požadavky na síť nebo databázi. Moderní knihovny (Ktor, Room) již podporují suspend funkce, což minimalizuje potřebu přímého použití async.
Často kladené otázky
launch vrací Job a nevrací výsledek provádění, zatímco async vrací Deferred<T> — objekt, ze kterého lze získat výsledek pomocí await(). launch se používá pro operace fire-and-forget, async — pro úlohy vracející data.
Nedoporučuje se. runBlocking na hlavním vlákně způsobuje ANR a blokuje UI. Používejte lifecycleScope.launch uvnitř Activity a Fragment — to je vestavěné řešení bez blokování.
Builder launch vrací objekt Job, který umožňuje řídit životní cyklus korutiny: zrušit (cancel), počkat na dokončení (join), zkontrolovat stav (isActive, isCompleted, isCancelled).
Deferred<T> — je asynchronní příslib výsledku vrácený builderem async. Dědí z Job a přidává metody await() pro získání výsledku, getCompleted() pro neblokující přístup a getCompletionExceptionOrNull() pro kontrolu výjimky.
Použijte parametr CoroutineStart.LAZY: scope.launch(start = CoroutineStart.LAZY) { ... }. Poté zavolejte job.start() nebo job.join() pro skutečné spuštění. To je užitečné pro odloženou inicializaci a podmíněné provádění korutin.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také