Coroutine Builder — functies van Kotlin Coroutines die coroutines creëren en starten, en de manier van uitvoering bepalen. De builders launch, async, runBlocking en produce dekken verschillende scenario's: van achtergrondtaken tot parallelle berekeningen met terugkeer van resultaat. Volgens JetBrains, 2024 is Coroutine Builder de basis van het coroutine-model en zorgt het voor gestructureerde concurrentie en levenscyclusbeheer.
Belangrijkste punten
Coroutine Builder — is een Kotlin-uitbreidingsfunctie die CoroutineScope en een suspend-blok accepteert, en een nieuwe coroutine creëert en start. Elke builder bepaalt hoe de coroutine wordt uitgevoerd: met of zonder resultaat, met blokkering van de thread of asynchroon. Builders zijn ingangspunten tot het coroutine-model van de taal.
Alle builders werken via CoroutineScope, die de levenscyclus van onderliggende coroutines beheert. Bij annulering van de scope worden alle coroutines die erdoor zijn gestart automatisch geannuleerd — dit is het principe van gestructureerde concurrentie. Deze aanpak voorkomt coroutine-lekken en garandeert een voorspelbare voltooiing.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Builders werken binnen CoroutineScope
val job = launch {
delay(1000L)
println("Wereld!")
}
println("Hallo,")
job.join()
}
Kotlin biedt vier ingebouwde coroutine-builders: launch, async, runBlocking en produce. Elk heeft zijn eigen retourtype en toepassingsgebied. Voor mobiele ontwikkeling op Android zijn launch en async de belangrijkste — ze werken niet-blokkerend en integreren met architectuurcomponenten.
| Builder | Retourtype | Thread-blokkering | Scenario |
|---|---|---|---|
| launch | Job | Nee | Fire-and-forget taken |
| async | Deferred<T> | Nee | Parallelle berekeningen |
| runBlocking | T | Ja | Testen, main-functie |
| produce | ReceiveChannel<E> | Nee | Streamgewijze overdracht (deprecated) |
Elke builder accepteert extra parameters: CoroutineStart (startstrategie), CoroutineContext (dispatcher, uitzonderingen) en een benoemd codeblok. Standaard wordt de coroutine onmiddellijk gestart (CoroutineStart.DEFAULT).
launch — de meest gebruikte builder in Android-ontwikkeling. Het start een coroutine die geen resultaat retourneert en geeft een Job-object terug voor het beheren van de levenscyclus. Dit is de ideale keuze voor operaties waarbij alleen een neveneffect nodig is: opslaan in database, verzenden van analytics, UI-update.
De builder launch accepteert CoroutineScope, optionele CoroutineContext en een suspend-blok. De geretourneerde Job maakt het mogelijk de coroutine te annuleren, op voltooiing te wachten of de status te controleren.
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val job: Job = scope.launch(CoroutineStart.LAZY) {
val data = fetchFromNetwork()
saveToDatabase(data)
}
job.start()
job.join()
De parameter CoroutineStart.LAZY stelt het starten uit tot een expliciete aanroep van start() of join(). Dit is handig voor uitgestelde initialisatie en voorwaardelijk starten. Voor standaard onmiddellijk starten wordt CoroutineStart.DEFAULT gebruikt of de parameter weggelaten.
async — builder die Deferred<T> retourneert — een asynchrone belofte van resultaat. De aanroep await() onderbreekt de coroutine tot het resultaat is verkregen, zonder de thread te blokkeren. Dit is het belangrijkste mechanisme voor parallelle taken in Kotlin-coroutines.
async is bijzonder effectief wanneer meerdere onafhankelijke operaties tegelijk moeten worden uitgevoerd. In tegenstelling tot sequentiële aanroep van suspend-functies, start async coroutines parallel, waardoor de totale uitvoeringstijd wordt verkort.
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 erft van Job, dus async ondersteunt alle levenscyclusoperaties: annuleren, wachten op voltooiing, afhandeling van uitzonderingen. Bij annulering van de scope worden onderliggende Deferred-coroutines automatisch geannuleerd.
runBlocking — de enige builder die de huidige thread blokkeert tot voltooiing van de coroutine. Het creëert een nieuwe CoroutineScope en start de doorgegeven coroutine, waarbij de aanroepende thread wordt geblokkeerd. Wordt gebruikt in ingangspunten main(), in testen en bij integratie met blocking-code.
runBlocking is gerechtvaardigd in drie scenario's: het ingangspunt van de applicatie (main), unittesten van suspend-functies en integratie met callback-gebaseerde bibliotheken waar suspend niet kan worden gebruikt. In productiecode van Android wordt het gebruik van runBlocking op de hoofdthread ten zeerste afgeraden.
class CoroutineTest {
@Test
fun `test suspend function`() = runBlocking {
val result = mySuspendFunction()
assertEquals("expected", result)
}
}
Voor testen wordt aanbevolen kotlinx-coroutines-test met TestCoroutineDispatcher te gebruiken in plaats van runBlocking — dit biedt tijdscontrole en voorkomt blokkades in de testomgeving.
De keuze van Coroutine Builder hangt af van het geretourneerde resultaat en het uitvoeringsscenario. Als de operatie geen gegevens retourneert — gebruik launch. Als het resultaat van een asynchrone operatie nodig is — async. runBlocking pas je alleen toe voor bridging, en produce vervang je door Flow voor reactieve streams.
In Android-projecten met Kotlin Coroutines zijn launch en async het belangrijkste paar builders. launch wordt gebruikt in ViewModel en UseCases voor het starten van coroutines, en async — voor parallelle verzoeken naar het netwerk of database. Moderne bibliotheken (Ktor, Room) ondersteunen al suspend-functies, wat de noodzaak van direct gebruik van async minimaliseert.
Veelgestelde vragen
launch retourneert Job en geeft geen uitvoeringsresultaat terug, terwijl async Deferred<T> retourneert — een object waaruit het resultaat via await() kan worden verkregen. launch wordt gebruikt voor fire-and-forget-operaties, async — voor taken die gegevens retourneren.
Wordt afgeraden. runBlocking op de hoofdthread veroorzaakt ANR en blokkeert de UI. Gebruik lifecycleScope.launch binnen Activity en Fragment — dit is een ingebouwde oplossing zonder blokkades.
De builder launch retourneert een Job-object waarmee de levenscyclus van de coroutine kan worden beheerd: annuleren (cancel), wachten op voltooiing (join), status controleren (isActive, isCompleted, isCancelled).
Deferred<T> — is een asynchrone belofte van resultaat, geretourneerd door de builder async. Het erft van Job en voegt methoden await() toe voor het verkrijgen van resultaat, getCompleted() voor niet-blokkerende toegang en getCompletionExceptionOrNull() voor controle op uitzonderingen.
Gebruik de parameter CoroutineStart.LAZY: scope.launch(start = CoroutineStart.LAZY) { ... }. Roep vervolgens job.start() of job.join() aan voor de daadwerkelijke start. Dit is handig voor uitgestelde initialisatie en voorwaardelijke uitvoering van coroutines.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook