launch — ein Coroutine Builder in Kotlin, der eine Coroutine startet, ohne ein Ergebnis zurückzugeben, und ein Job-Objekt zur Steuerung der Ausführung zurückliefert. Dieser Builder implementiert das Fire-and-Forget-Muster: Die Coroutine beginnt ihre Arbeit im Hintergrundthread und wird automatisch abgeschlossen. Laut der JetBrains-Dokumentation, 2024, ist launch die primäre Methode zum Ausführen paralleler Aufgaben in Kotlin Coroutines.
Wichtige Punkte
launch ist eine Kotlin-Erweiterungsfunktion, verfügbar über den Import kotlinx.coroutines, die eine neue Coroutine in einem bestimmten CoroutineScope erstellt. Im Gegensatz zu normalen Funktionen wird der Code innerhalb von launch nebenläufig ausgeführt — die Coroutine kann sich suspendieren, ohne einen Thread zu blockieren, und später wieder aufnehmen.
Der launch-Builder ist ein grundlegender Baustein des Kotlin-Coroutine-Modells. Er gibt keinen berechneten Wert zurück, sondern ein Job-Objekt, das die Kontrolle über die Coroutine-Ausführung ermöglicht. Alle Kind-Coroutinen, die über launch innerhalb einer anderen Coroutine gestartet werden, sind an die Eltern-Coroutine gebunden.
Der launch-Builder ist als Inline-Funktion mit mehreren Parametern definiert: CoroutineScope, CoroutineContext, CoroutineStart und einem suspend-Block. Die Parameter haben Standardwerte, was launch für typische Szenarien praktisch macht.
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
Der context-Parameter akzeptiert einen CoroutineContext, der einen Dispatcher, einen Ausnahmehandler und ein benanntes Element kombiniert. Am häufigsten werden Dispatchers.IO, Dispatchers.Main oder SupervisorJob zur Fehlerisolierung übergeben.
Job — das zurückgegebene Objekt, das den Lebenszyklus der Coroutine repräsentiert. Ein Job kann sich in folgenden Zuständen befinden: New, Active, Completing, Completed, Cancelling, Cancelled. Jeder Zustand spiegelt den Ausführungsstatus wider und ermöglicht Reaktionen auf Änderungen.
val job = CoroutineScope(Dispatchers.IO).launch {
repeat(10) { i ->
delay(1000L)
println("Fortschritt: $i")
}
}
println("Job ist aktiv: ${job.isActive}")
delay(2500L)
job.cancel()
println("Job ist gecancelt: ${job.isCancelled}")
Job unterstützt eine Hierarchie: Wenn eine Eltern-Coroutine gecancelt wird, werden alle Kind-Coroutinen automatisch gecancelt. SupervisorJob ändert dieses Verhalten — Kind-Coroutinen werden nicht gecancelt, wenn eine von ihnen fehlschlägt.
Strukturierte Nebenläufigkeit bedeutet, dass jede Coroutine innerhalb eines bestimmten CoroutineScope gestartet wird und der Scope erst abgeschlossen wird, wenn alle Kind-Coroutinen ihre Arbeit beendet haben. launch unterstützt dieses Prinzip vollständig — Coroutinen, die innerhalb einer anderen Coroutine gestartet werden, sind deren Kinder.
Bei verschachtelten launch-Aufrufen entsteht ein Coroutine-Baum. Die Eltern-Coroutine wartet auf die Fertigstellung aller Kinder, was eine vorhersagbare Ausführungsreihenfolge garantiert und die Ressourcenverwaltung vereinfacht.
fun main() = runBlocking {
launch {
launch {
delay(1000L)
println("Kind 1 abgeschlossen")
}
launch {
delay(500L)
println("Kind 2 abgeschlossen")
}
println("Alle Kinder abschlossen vor dieser Zeile")
}
}
Dieses Verhalten unterscheidet sich von der thread-basierten Nebenläufigkeit, bei der Kind-Threads nicht an den Eltern-Thread gebunden sind. Bei Coroutinen wird die Eltern-Coroutine nicht abgeschlossen, bis alle Kinder ihre Arbeit beendet haben.
Die Ausnahmebehandlung in launch hängt vom Job-Typ ab. Bei einem normalen Job propagieren Ausnahmen an die Eltern-Coroutine und canceln sie. Bei SupervisorJob oder SupervisorScope werden Ausnahmen isoliert — ein Fehler in einer Kind-Coroutine wirkt sich nicht auf die anderen aus.
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try {
riskyOperation()
} catch (e: Exception) {
println("Gefangen: ${e.message}")
}
}
scope.launch {
println("Dies läuft dank SupervisorJob weiter")
}
Zur globalen Behandlung von nicht abgefangenen Ausnahmen wird CoroutineExceptionHandler verwendet. Er fängt Ausnahmen, die innerhalb der Coroutine nicht behandelt wurden, und ermöglicht die Protokollierung des Fehlers, ohne die Anwendung zum Absturz zu bringen.
In Android wird launch überall eingesetzt: von ViewModel bis WorkManager. Das Hauptmuster ist die Verwendung von lifecycleScope im Fragment und viewModelScope im ViewModel zur automatischen Cancellation von Coroutinen bei Beendigung des Komponentenlebenszyklus.
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 cancelt Coroutinen automatisch, wenn das ViewModel zerstört wird. Dies verhindert Speicherlecks und stellt sicher, dass Hintergrundoperationen nach dem Verlust des Kontexts nicht fortgesetzt werden. Zusätzlich kann withContext zum Wechseln zwischen Dispatchern verwendet werden.
Häufig gestellte Fragen
launch gibt ein Job zurück und kein Ergebnis, während async Deferred<T> zur Ergebnisermittlung zurückgibt. launch wird für Fire-and-Forget-Operationen verwendet, async — wenn Sie auf den zurückgegebenen Wert warten und ihn verwenden müssen.
Rufen Sie job.cancel() auf dem gespeicherten Job-Objekt auf. Für Gruppen-Cancellation canceln Sie den gesamten CoroutineScope über scope.cancel(). Die Coroutine muss kooperativ sein — isActive prüfen oder cancellierbare suspend-Funktionen verwenden.
Verwenden Sie try-catch innerhalb des launch-Blocks oder übergeben Sie CoroutineExceptionHandler im CoroutineContext. Zur Fehlerisolierung verwenden Sie SupervisorJob — dann cancelt eine Ausnahme in einer Kind-Coroutine die anderen nicht.
Nein, launch ist eine Erweiterungsfunktion von CoroutineScope. Ohne Scope kann die Coroutine nicht dem Prinzip der strukturierten Nebenläufigkeit folgen. Verwenden Sie GlobalScope.launch mit Vorsicht — es erstellt eine Coroutine ohne Lebenszyklusbindung.
Die Anzahl ist durch den Thread-Pool des Dispatchers begrenzt. Dispatchers.Default verwendet so viele Threads wie CPU-Kerne vorhanden sind. Dispatchers.IO unterstützt bis zu 64 Threads. Werden mehr Coroutinen gestartet, werden sie in die Warteschlange gestellt.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch