Les coroutines Kotlin fournissent une API qui vous permet d'écrire du code asynchrone. Les coroutines Kotlin vous permettent de définir un élément CoroutineScope, qui vous aide à gérer le moment où vos coroutines doivent s'exécuter. Chaque opération asynchrone s'exécute dans un champ d'application particulier.
Les composants tenant compte des cycles de vie offrent une compatibilité de premier ordre pour les coroutines des champs d'application logiques de votre application. Ce document explique comment utiliser efficacement les coroutines avec des composants tenant compte du cycle de vie.
Ajouter des dépendances
Les champs d'application de coroutine intégrés décrits dans cet article sont contenus dans l'API Lifecycle. Veillez à ajouter les dépendances appropriées lorsque vous utilisez ces champs d'application.
- Pour les utilitaires ViewModel dans Compose, utilisez
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:$lifecycle_version"). - Pour les utilitaires Lifecycle dans Compose, utilisez
implementation("androidx.lifecycle:lifecycle-runtime-compose:$lifecycle_version").
Champs d'application des coroutines tenant compte du cycle de vie
Compose et les bibliothèques Lifecycle fournissent les champs d'application intégrés suivants que vous pouvez utiliser dans votre application.
ViewModelScope
Un élément ViewModelScope est défini pour chaque élément ViewModel de votre appli. Toute coroutine lancée dans ce champ d'application est automatiquement annulée si l'élément ViewModel est effacé. Les coroutines sont utiles ici si des tâches ne doivent être effectuées que si l'élément ViewModel est actif. Par exemple, si vous calculez des données pour une mise en page, vous devez limiter la tâche à l'élément ViewModel. Si l'élément ViewModel est effacé, la tâche est automatiquement annulée pour éviter de consommer des ressources.
Vous pouvez accéder à l'élément CoroutineScope d'un élément ViewModel via la propriété viewModelScope de l'élément ViewModel, comme indiqué dans l'exemple suivant :
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// Coroutine that will be canceled when the ViewModel is cleared.
}
}
}
Pour des cas d'utilisation plus avancés, vous pouvez transmettre un CoroutineScope personnalisé directement dans le constructeur du ViewModel pour remplacer le viewModelScope par défaut. Cette approche offre plus de contrôle et de flexibilité, en particulier pour :
Tests : il vous permet d'injecter un
TestScope, ce qui facilite le contrôle du temps et la vérification du comportement des coroutines dans les tests unitaires.Configuration personnalisée : vous pouvez configurer le champ d'application avec un
CoroutineDispatcherspécifique (commeDispatchers.Defaultpour les calculs lourds) ou unCoroutineExceptionHandlerpersonnalisé avant même que le ViewModel ne commence son travail.
Champs d'application liés à la composition
Les effets secondaires tels que les animations, les appels réseau ou les minuteurs doivent être limités au cycle de vie du composable. Ainsi, lorsqu'un composable quitte l'écran (quitte la composition), toutes les coroutines en cours d'exécution sont automatiquement annulées pour éviter les fuites de mémoire.
Compose fournit l'API LaunchedEffect pour gérer le champ d'application de la composition de manière déclarative.
LaunchedEffect crée un CoroutineScope qui vous permet d'exécuter des fonctions de suspension. Le champ d'application est lié au cycle de vie de la composition du composable, et non au cycle de vie de l'activité hôte.
- Entrée : la coroutine démarre lorsque le composable entre dans la composition.
- Sortie : la coroutine est annulée lorsque le composable quitte la composition.
- Relance : si une clé transmise à
LaunchedEffectchange, la coroutine existante est annulée et une nouvelle est lancée.
L'exemple suivant montre comment utiliser LaunchedEffect pour créer une animation de pulsation. La coroutine est liée à la présence du composable dans la composition et réagit aux changements de configuration :
// 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) } }
Pour en savoir plus sur LaunchedEffect, consultez Effets secondaires dans Compose.
Collecte de flux tenant compte du cycle de vie
Pour collecter des flux en toute sécurité dans Jetpack Compose, utilisez l'API collectAsStateWithLifecycle. Cette fonction unique convertit un Flow en objet Compose State et gère automatiquement l'abonnement au cycle de vie pour vous. Par défaut, la collecte commence lorsque le cycle de vie est STARTED et s'arrête lorsque le cycle de vie est STOPPED. Pour remplacer ce comportement par défaut, transmettez le paramètre minActiveState avec la méthode de cycle de vie de votre choix, par exemple Lifecycle.State.RESUMED.
L'exemple suivant montre comment collecter le StateFlow d'un ViewModel dans un composable :
@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) /* ... */ }
Collecte parallèle de plusieurs flux
Dans Compose, vous pouvez collecter plusieurs flux en parallèle en déclarant plusieurs variables d'état. Comme collectAsStateWithLifecycle gère son propre champ d'application sous-jacent, la collecte parallèle est gérée automatiquement :
@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()
// ...
}
Calculer des valeurs de manière asynchrone à l'aide de flux
Lorsque vous devez calculer des valeurs de manière asynchrone, utilisez StateFlow avec l'opérateur stateIn.
L'extrait de code suivant utilise un Flow standard converti en StateFlow. Le paramètre WhileSubscribed(5000) maintient l'abonnement actif pendant cinq secondes après la disparition de l'UI pour gérer les modifications de configuration.
val uiState: StateFlow<Result> = flow {
emit(repository.fetchData())
}
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = Result.Loading
)
Utilisez collectAsStateWithLifecycle pour convertir les valeurs collectées en State Compose, afin que votre UI puisse se mettre à jour de manière réactive chaque fois que les données changent.
Pour en savoir plus sur l'état, consultez États et Jetpack Compose.
Ressources supplémentaires
Contenu des vues
Exemples
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Gérer les cycles de vie à l'aide de composants tenant compte des cycles de vie
- Charger et afficher des données paginées