Kotlin-Coroutinen bieten eine API, mit der Sie asynchronen Code schreiben können. Mit Kotlin-Coroutinen können Sie einen CoroutineScope definieren, mit dem Sie verwalten können, wann Ihre Coroutinen ausgeführt werden sollen. Jeder asynchrone Vorgang wird in einem bestimmten Bereich ausgeführt.
Lebenszyklusbewusste Komponenten bieten erstklassige Unterstützung für Coroutinen für logische Bereiche in Ihrer App. In diesem Dokument wird erläutert, wie Sie Coroutinen effektiv mit lebenszyklusbewussten Komponenten verwenden.
Abhängigkeiten hinzufügen
Die in diesem Thema beschriebenen integrierten Coroutine-Scopes sind in der Lifecycle API enthalten. Achten Sie darauf, die entsprechenden Abhängigkeiten hinzuzufügen, wenn Sie diese Bereiche verwenden.
- Verwenden Sie
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version")für ViewModel-Hilfsprogramme in Compose. - Verwenden Sie für Lifecycle-Dienstprogramme in Compose
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version").
Lebenszyklusbezogene Coroutine-Scopes
Compose und die Lifecycle-Bibliotheken bieten die folgenden integrierten Bereiche, die Sie in Ihrer App verwenden können.
ViewModelScope
Für jedes ViewModel in Ihrer App wird ein ViewModelScope definiert. Jede in diesem Bereich gestartete Coroutine wird automatisch abgebrochen, wenn das ViewModel gelöscht wird. Coroutinen sind hier nützlich, wenn Sie Aufgaben haben, die nur ausgeführt werden müssen, wenn ViewModel aktiv ist. Wenn Sie beispielsweise Daten für ein Layout berechnen, sollten Sie die Arbeit auf das ViewModel beschränken. Wenn das ViewModel gelöscht wird, wird die Arbeit automatisch abgebrochen, um Ressourcen zu sparen.
Sie können über das Attribut viewModelScope des ViewModel auf das CoroutineScope eines ViewModel zugreifen, wie im folgenden Beispiel gezeigt:
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
Bei komplexeren Anwendungsfällen können Sie ein benutzerdefiniertes CoroutineScope direkt an den Konstruktor des ViewModels übergeben, um das Standard-viewModelScope zu ersetzen. Dieser Ansatz bietet mehr Kontrolle und Flexibilität, insbesondere für:
Testen: Sie können eine
TestScopeeinschleusen, um die Zeit in Unittests besser zu steuern und das Verhalten von Koroutinen zu überprüfen.Benutzerdefinierte Konfiguration: Sie können den Bereich mit einem bestimmten
CoroutineDispatcher(z. B.Dispatchers.Defaultfür rechenintensive Vorgänge) oder einem benutzerdefiniertenCoroutineExceptionHandlerkonfigurieren, bevor das ViewModel seine Arbeit aufnimmt.
Kompositionsgebundene Bereiche
Nebenwirkungen wie Animationen, Netzwerkaufrufe oder Timer müssen auf den Lebenszyklus des Composables beschränkt sein. Wenn ein Composable den Bildschirm verlässt (die Komposition beendet), werden alle laufenden Koroutinen automatisch abgebrochen, um Speicherlecks zu vermeiden.
Compose bietet die LaunchedEffect API, um den Umfang von Composables deklarativ zu verarbeiten.
Mit LaunchedEffect wird ein CoroutineScope erstellt, mit dem Sie suspend-Funktionen ausführen können. Der Bereich ist an den Kompositionslebenszyklus des Composables gebunden, nicht an den Lebenszyklus der Host-Aktivität.
- Eingabe: Die Coroutine wird gestartet, wenn die Composable in die Komposition aufgenommen wird.
- Beenden: Die Coroutine wird abgebrochen, wenn die Composable die Komposition verlässt.
- Neustart: Wenn sich ein an
LaunchedEffectübergebener Schlüssel ändert, wird die vorhandene Coroutine abgebrochen und eine neue gestartet.
Im folgenden Beispiel wird gezeigt, wie Sie mit LaunchedEffect eine pulsierende Animation erstellen. Die Coroutine ist an die Präsenz des Composables in der Komposition gebunden und reagiert auf Konfigurationsänderungen:
// Allow the pulse rate to be configured, so it can be sped up if the user is running // out of time var pulseRateMs by remember { mutableLongStateOf(3000L) } val alpha = remember { Animatable(1f) } LaunchedEffect(pulseRateMs) { // Restart the effect when the pulse rate changes while (isActive) { delay(pulseRateMs) // Pulse the alpha every pulseRateMs to alert the user alpha.animateTo(0f) alpha.animateTo(1f) } }
Weitere Informationen zu LaunchedEffect finden Sie unter Nebeneffekte in Compose.
Erfassung von Flows mit Berücksichtigung des Lebenszyklus
Verwenden Sie die API collectAsStateWithLifecycle, um Flows in Jetpack Compose sicher zu erfassen. Diese einzelne Funktion konvertiert ein Flow in ein Compose-State-Objekt und verwaltet automatisch das Abo für den Lebenszyklus für Sie. Standardmäßig beginnt die Erfassung, wenn der Lebenszyklus STARTED ist, und endet, wenn der Lebenszyklus STOPPED ist. Wenn Sie dieses Standardverhalten überschreiben möchten, übergeben Sie den Parameter minActiveState mit der gewünschten Lebenszyklusmethode, z. B. Lifecycle.State.RESUMED.
Das folgende Beispiel zeigt, wie die StateFlow eines ViewModels in einer Composable-Funktion erfasst werden:
@Composable private fun ConversationScreen( conversationViewModel: ConversationViewModel = viewModel() ) { val messages by conversationViewModel.messages.collectAsStateWithLifecycle() ConversationScreen( messages = messages, onSendMessage = { message: Message -> conversationViewModel.sendMessage(message) } ) } @Composable private fun ConversationScreen( messages: List<Message>, onSendMessage: (Message) -> Unit ) { MessagesList(messages, onSendMessage) /* ... */ }
Parallele Erfassung mehrerer Streams
In Compose können Sie mehrere Flows parallel erfassen, indem Sie mehrere Statusvariablen deklarieren. Da collectAsStateWithLifecycle seinen eigenen zugrunde liegenden Bereich verwaltet, wird die parallele Erfassung automatisch verarbeitet:
@Composable
fun DashboardScreen(viewModel: DashboardViewModel = viewModel()) {
// Both flows are collected safely in parallel and will emit updates when either changes, the composables will recompose
val userData by viewModel.userFlow.collectAsStateWithLifecycle()
val feedData by viewModel.feedFlow.collectAsStateWithLifecycle()
// ...
}
Werte asynchron mit Flows berechnen
Wenn Sie Werte asynchron berechnen müssen, verwenden Sie StateFlow mit dem Operator stateIn.
Im folgenden Snippet wird ein Standard-Flow verwendet, der in ein StateFlow konvertiert wurde. Der Parameter WhileSubscribed(5000) hält das Abo nach dem Schließen der Benutzeroberfläche fünf Sekunden lang aktiv, um Konfigurationsänderungen zu verarbeiten.
val uiState: StateFlow<Result> = flow {
emit(repository.fetchData())
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = Result.Loading
)
Verwenden Sie collectAsStateWithLifecycle, um die erfassten Werte in Compose-State zu konvertieren, damit Ihre Benutzeroberfläche reaktiv aktualisiert werden kann, wenn sich die Daten ändern.
Weitere Informationen zum Status finden Sie unter Status und Jetpack Compose.
Zusätzliche Ressourcen
Inhalte ansehen
Beispiele
Empfehlungen für Sie
- Hinweis: Linktext wird angezeigt, wenn JavaScript deaktiviert ist.
- Umgang mit Lebenszyklen mit lebenszyklusbewussten Komponenten
- Paginierte Daten laden und anzeigen