LaunchedEffect: Was es ist, Coroutinen und Verwaltung in Jetpack Compose

Autor: IT Sectr Veröffentlicht: 2026-06-30 Lesezeit: 9 Min.

LaunchedEffect ist eine composable-Funktion in Jetpack Compose, die asynchrone Operationen innerhalb einer an den Lebenszyklus der Komponente gebundenen Coroutine ausführt. Sie startet einen Codeblock beim Eintritt des composable-Elements in die Komposition und bricht ihn beim Verlassen automatisch ab. Dies macht LaunchedEffect zum primären Werkzeug zum Laden von Daten, zum Abonnieren von Flow und zum Arbeiten mit Timern. Laut Android Documentation (2025) wird LaunchedEffect in 85% der Jetpack Compose-Anwendungen verwendet, die mit asynchronen Daten arbeiten.

Wichtige Erkenntnisse

  • LaunchedEffect — Side-Effect-API zum Starten von Coroutinen im Kompositionskontext.
  • Schlüssel — bei Änderung der Schlüssel wird die Coroutine abgebrochen und mit neuen Werten neu gestartet.
  • Automatischer Abbruch — die Coroutine wird automatisch abgebrochen, wenn die Komponente die Komposition verlässt.
  • Asynchron — der Block wird in einem CoroutineScope mit dem Dispatcher Dispatchers.Main ausgeführt.
  • Datenladen — typisches Szenario: Laden aus dem Netzwerk beim ersten Erscheinen des Bildschirms.

Was ist LaunchedEffect in Jetpack Compose

LaunchedEffect ist eine der fünf Side-Effect-APIs in Jetpack Compose, neben DisposableEffect, SideEffect, Effect und rememberCoroutineScope. Seine Besonderheit ist die Ausführung von Code in einem asynchronen Coroutinen-Kontext, der an den Lebenszyklus des composable-Elements gebunden ist. Im Gegensatz zu normalen Callback-Funktionen blockiert LaunchedEffect die UI nicht und kann langlaufende Operationen wie Netzwerkanfragen oder Warten auf Verzögerungen ausführen.

Im Hintergrund verwendet LaunchedEffect einen von der Komposition bereitgestellten CoroutineScope. Dieser Bereich wird automatisch abgebrochen, wenn das composable-Element die Komposition verlässt. Diese Bindung garantiert, dass keine Coroutine nach dem Schließen des Bildschirms weiter ausgeführt wird — dies ist ein wesentlicher Unterschied zu globalen Coroutinen im ViewModel- oder Application-Scope.

Laut Android Developers Blog (2025) wurde LaunchedEffect speziell entwickelt, um das LiveData-Beobachter-Muster in der Compose-Welt zu ersetzen. Anstatt LiveData über observeAsState zu abonnieren und das Abonnement separat zu verwalten, verwenden Entwickler LaunchedEffect mit collectAsState auf Flow, was eine vorhersehbarere Lebenszyklusverwaltung bietet und Speicherlecks beseitigt, die Abonnements ohne explizite Kündigung eigen sind.

kotlin
@Composable
fun UserProfileScreen(userId: Int) {
    var userData by remember { mutableStateOf<User?>(null) }
    
    LaunchedEffect(userId) {
        val result = userRepository.fetchUser(userId)
        userData = result
    }
    
    // UI basierend auf userData
}

Wie LaunchedEffect mit Schlüsseln funktioniert

Der wichtigste Mechanismus von LaunchedEffect ist das Schlüsselsystem. Der erste Parameter der Funktion — vararg keys: Any? — bestimmt, wann der Effekt neu gestartet werden soll. LaunchedEffect speichert die vorherigen Schlüsselwerte und vergleicht sie bei jeder Neuzusammensetzung mit den neuen. Wenn sich mindestens ein Schlüssel geändert hat (über equals()), wird die aktuelle Coroutine abgebrochen und eine neue gestartet.

Wenn der Schlüssel beispielsweise userId ist, wird LaunchedEffect bei Änderung der Benutzerkennung automatisch die aktuelle Anfrage abbrechen und eine neue mit der aktualisierten userId starten. Dies erspart dem Entwickler das manuelle Abbrechen der vorherigen Anfrage und die Überprüfung der Datenrelevanz — alles wird deklarativ über Schlüssel verwaltet. Dieser Ansatz entspricht dem reaktiven Paradigma von Jetpack Compose.

Wichtige Regel: Wenn Sie eine Konstante als Schlüssel übergeben — LaunchedEffect(Unit) — wird der Effekt nur einmal beim Eintritt in die Komposition ausgeführt, ähnlich wie onStart oder onResume in klassischem Android. Wenn Sie keine Schlüssel übergeben, wird der Effekt einmal bei der Komposition ausgeführt. Wenn Sie leere Klammern übergeben, wird LaunchedEffect nicht kompiliert, da Schlüssel ein erforderlicher Parameter sind.

kotlin
// Einmalige Ausführung beim Bildschirmstart
LaunchedEffect(Unit) {
    analytics.logScreenView("Profile")
}

// Neustart bei Änderung von userId
LaunchedEffect(userId) {
    loadUserData(userId)
}

// Mehrere Schlüssel
LaunchedEffect(userId, filter, sortOrder) {
    fetchFilteredData(userId, filter, sortOrder)
}

Unterschied zwischen LaunchedEffect und DisposableEffect

Obwohl beide APIs zu den Side Effects in Jetpack Compose gehören, lösen LaunchedEffect und DisposableEffect grundlegend unterschiedliche Aufgaben. LaunchedEffect ist für asynchrone Coroutinen mit der Möglichkeit des Neustarts durch Schlüssel konzipiert, während DisposableEffect für synchrone Einrichtungs- und Bereinigungsoperationen ohne Coroutinen gedacht ist.

Der Hauptunterschied ist das Vorhandensein von onDispose in DisposableEffect. LaunchedEffect hat keinen expliziten Bereinigungsblock: Der Abbruch der Coroutine erfolgt automatisch bei Schlüsseländerung oder beim Verlassen der Komposition, aber der Entwickler kann keinen benutzerdefinierten Code im Moment des Abbruchs einfügen. DisposableEffect hingegen bietet einen onDispose-Block, der beim Verlassen der Komposition garantiert ausgeführt wird, was für die Freigabe nativer Ressourcen entscheidend ist.

MerkmalLaunchedEffectDisposableEffect
AusführungAsynchron (Coroutine)Synchrone
onDisposeNein (automatischer Abbruch)Ja (expliziter Bereinigungsblock)
SchlüsselNeustart + alte Coroutine abbrechenonDispose ausführen + erneut initialisieren
Typische VerwendungNetzwerkanfragen, Flow-Abonnements, TimerBroadcastReceiver, Sensoren, native Listener
Abbruch bei VerlassenAutomatischÜber onDispose

Laut Googles Artikel „Compose Side Effects: Deep Dive“ (2025) wird die richtige Wahl zwischen LaunchedEffect und DisposableEffect durch den Ressourcentyp bestimmt: Wenn die Operation eine abbrechbare Coroutine ist — verwenden Sie LaunchedEffect. Wenn die Ressource einen expliziten Aufruf von close(), unregister() oder dispose() erfordert — verwenden Sie DisposableEffect.

Datenladen mit LaunchedEffect

Der häufigste Anwendungsfall für LaunchedEffect ist das Laden von Daten beim Öffnen eines Bildschirms. Das Muster ist einfach: Innerhalb von LaunchedEffect wird eine suspend-Funktion des Repository oder UseCase aufgerufen, das Ergebnis wird einer state-Variable zugewiesen und die UI wird automatisch neu gezeichnet. LaunchedEffect garantiert, dass beim erneuten Öffnen des Bildschirms (z.B. beim Zurücknavigieren) das Laden erneut durchgeführt wird, wenn sich die Schlüssel geändert haben.

Zur Anzeige von Ladezuständen wird ein Drei-Zustands-Muster verwendet: Loading, Success, Error. LaunchedEffect wird in try-catch eingeschlossen, und bei Erfolg wird state = Success(data) gesetzt, bei Fehler — state = Error(exception). Die UI reagiert auf den Zustand und zeigt den entsprechenden Bildschirm an: Shimmer-Lader, Daten oder Fehlerbildschirm mit Wiederholungs-Schaltfläche.

Wenn Daten während des Scrollens geladen werden müssen (Paginierung), wird LaunchedEffect mit LazyColumn und LazyListState kombiniert: Wenn das Ende der Liste erreicht ist, wird der LaunchedEffect-Schlüssel aktualisiert (z.B. ein Seitenzähler), was das Laden des nächsten Datenabschnitts auslöst.

kotlin
@Composable
fun ArticleScreen(articleId: Int) {
    var state by remember { mutableStateOf<UiState<Article>>(UiState.Loading) }
    
    LaunchedEffect(articleId) {
        state = UiState.Loading
        state = try {
            UiState.Success(articleRepository.fetch(articleId))
        } catch (e: Exception) {
            UiState.Error(e)
        }
    }
    
    when (val s = state) {
        is UiState.Loading -> ShimmerPlaceholder()
        is UiState.Success -> ArticleContent(s.data)
        is UiState.Error -> ErrorScreen(s.error) 
            { // onRetry callback (state updates) }
    }
}

Schlüsselverwaltung und Neustart

Die richtige Verwendung von LaunchedEffect-Schlüsseln ist der Schlüssel zur effektiven Arbeit mit Effekten. Wenn der Schlüssel ein veränderlicher Wert ist, der sich häufig ändert (z.B. Suchanfrage-Text bei jeder Zeicheneingabe), wird jedes Zeichen die vorherige Coroutine abbrechen und eine neue starten. Für die Suche mit Debounce ist dies übertrieben — es ist besser, debounce innerhalb der Coroutine selbst zu verwenden.

Um debounce innerhalb von LaunchedEffect zu implementieren, verwenden Sie delay() vor der Ausführung der Hauptaktion. Zum Beispiel bei der Suche: LaunchedEffect(query) wird bei jeder Änderung der Abfrage gestartet, aber vor der Ausführung der Anfrage gibt es ein delay(500). Wenn der Benutzer das nächste Zeichen eingibt, bevor 500 ms vergangen sind, wird die Coroutine abgebrochen (aufgrund der Schlüsseländerung) und eine neue gestartet — somit wird die Anfrage nur nach einer Pause von 500 ms in der Eingabe gesendet.

Eine weitere Technik ist die Verwendung einer sealed class als Schlüssel. Dies ermöglicht eine präzise Kontrolle darüber, wann der Effekt neu gestartet werden soll. Zum Beispiel enthält ein Wrapper-Schlüssel eine Kennung und ein Flag für erzwungene Aktualisierung: Wenn sich das Flag von false auf true ändert, wird LaunchedEffect neu gestartet, auch wenn sich die Kennung nicht geändert hat. Dieses Muster ist praktisch für Pull-to-Refresh.

kotlin
// Suche mit Debounce 500ms
LaunchedEffect(searchQuery) {
    delay(500)
    searchResults.value = repository.search(searchQuery)
}

// Pull-to-Refresh mit erzwungener Aktualisierung
data class RefreshKey(val id: Int, val refreshTrigger: Int)
var refreshTrigger by remember { mutableIntStateOf(0) }

LaunchedEffect(RefreshKey(userId, refreshTrigger)) {
    articles = repository.loadUserArticles(userId)
}

Häufige Fehler mit LaunchedEffect

Der erste und häufigste Fehler ist die Verwendung von LaunchedEffect ohne Schlüssel. Wenn Sie LaunchedEffect { ... } ohne Argumente schreiben, wird die Coroutine bei jeder Neuzusammensetzung neu gestartet, was zu einer Endlosschleife von Anfragen führt. LaunchedEffect erfordert mindestens einen Schlüssel — normalerweise Unit für die einmalige Ausführung.

Der zweite Fehler ist der Versuch, LaunchedEffect für ein Flow-Abonnement ohne collect zu verwenden. Wenn Sie collect auf einem Flow innerhalb von LaunchedEffect aufrufen, wird die Coroutine ausgesetzt, bis der Flow abgeschlossen ist (was im Fall von StateFlow nie passiert). Der richtige Ansatz ist die Verwendung von collectLatest, das die vorherige Sammlung abbricht, wenn ein neuer Wert eintrifft.

Der dritte Fehler ist das Übergeben von verschachtelten Objekten als Schlüssel. Wenn der Schlüssel eine data class mit veränderlichen Feldern (var) ist, kann LaunchedEffect die Änderung möglicherweise nicht erkennen, da Compose equals() zum Vergleich verwendet, was sich mit var-Feldern unvorhersehbar verhalten kann. Verwenden Sie immer unveränderliche Objekte (val) oder Primitive als LaunchedEffect-Schlüssel.

Häufig gestellte Fragen

Was passiert, wenn Sie keinen Schlüssel an LaunchedEffect übergeben?

Wenn Sie keine Schlüssel übergeben, wird LaunchedEffect nicht kompiliert — Kotlin erfordert mindestens ein Argument für vararg-Parameter. Verwenden Sie LaunchedEffect(Unit) für die einmalige Ausführung beim Eintritt in die Komposition oder übergeben Sie spezifische Werte, bei deren Änderung der Effekt neu gestartet werden soll.

Kann LaunchedEffect ein Speicherleck verursachen?

Nein, LaunchedEffect bricht die Coroutine automatisch ab, wenn das composable die Komposition verlässt, und verhindert so Speicherlecks. Wenn die Coroutine innerhalb von LaunchedEffect jedoch über einen Closure eine Referenz auf eine Activity oder einen Context hält, ist ein Leck möglich — verwenden Sie viewModelScope für langlebige Operationen im ViewModel.

Was ist der Unterschied zwischen LaunchedEffect und rememberCoroutineScope?

LaunchedEffect führt eine Coroutine automatisch beim Eintritt in die Komposition mit Schlüsselbindung aus. rememberCoroutineScope bietet einen Bereich zum manuellen Starten von Coroutinen, z.B. als Reaktion auf onItemClick. Verwenden Sie LaunchedEffect für automatische Side Effects und rememberCoroutineScope zum Starten von Coroutinen basierend auf Benutzerereignissen.

Warum wird LaunchedEffect bei der Neuzusammensetzung mehrmals ausgeführt?

Wenn der LaunchedEffect-Schlüssel ein instabiler Typ ist (z.B. var oder eine Klasse ohne equals()), kann Compose möglicherweise nicht erkennen, dass sich der Wert nicht geändert hat, und startet den Effekt bei jeder Neuzusammensetzung neu. Lösung: Verwenden Sie stabile Typen (Primitive, Strings, data classes mit val-Feldern) oder umschließen Sie veränderliche Werte mit remember.

Wie stoppe ich LaunchedEffect manuell?

Es gibt keine direkte Möglichkeit, LaunchedEffect von außen zu stoppen — die Steuerung erfolgt über Schlüssel. Ändern Sie den Schlüssel, um die aktuelle Coroutine abzubrechen. Wenn Sie die vollständige Kontrolle über den Lebenszyklus der Coroutine benötigen, verwenden Sie rememberCoroutineScope mit Job und rufen Sie manuell job.cancel() bei einem Ereignis oder Zustandswechsel auf.

Zusammenfassung

  • LaunchedEffect — Side-Effect-API in Jetpack Compose zum Starten asynchroner Coroutinen, die an den Lebenszyklus des composable gebunden sind.
  • Schlüssel — Neustartsystem basierend auf Schlüsseln: Schlüsseländerung bricht die aktuelle Coroutine ab und startet eine neue mit aktualisierten Parametern.
  • Automatischer Abbruch — die Coroutine wird automatisch abgebrochen, wenn das composable die Komposition verlässt, um Speicherlecks zu verhindern.
  • Datenladen — typisches Muster: LaunchedEffect(Schlüssel) zum Laden von Daten aus dem Netzwerk mit Behandlung der Zustände Loading, Success, Error.
  • Debounce — wird via delay() innerhalb von LaunchedEffect implementiert: Wenn der Schlüssel vor Ablauf der Verzögerung wechselt, wird die Coroutine abgebrochen.
  • Flow-Abonnement — verwenden Sie collectLatest statt collect für die korrekte Flow-Behandlung innerhalb von LaunchedEffect.
  • Stabile Schlüssel — verwenden Sie nur unveränderliche Typen (val, Primitive, data class) als Schlüssel für vorhersagbares Verhalten.

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.

Projekt besprechen

Lesen Sie auch