Comment configurer et utiliser les coroutines dans des projets Kotlin?
sobes.tech IA
Réponse de l'IA
Pour configurer les coroutines, il est nécessaire d'ajouter la dépendance correspondante dans le fichier build.gradle.
// build.gradle (module app)
dependencies {
//... autres dépendances
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Pour JVM, Android, JS, Native
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Pour Android (si Dispatchers.Main est nécessaire)
}
L'utilisation des coroutines inclut :
-
Portée (Scope) : Définir la portée dans laquelle les coroutines s'exécuteront et gérer leur cycle de vie.
GlobalScope: Portée de toute l'application, à utiliser avec précaution, car cela peut entraîner des fuites de mémoire.CoroutineScope: Créé explicitement, permet de contrôler l'annulation des coroutines.- Portées prédéfinies dans les frameworks (par exemple,
lifecycleScopedans Android ViewModel).
// Exemple avec CoroutineScope val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // Création d'une portée avec Dispatcher et Job fun performBackgroundTask() { myScope.launch { // Lancer une coroutine // Processus de calcul long } } fun cancelAllTasks() { myScope.cancel() // Annuler toutes les coroutines dans la portée } -
Constructeurs de coroutines (Builders) : Fonctions pour lancer des coroutines.
launch: Lance une coroutine qui ne retourne pas de résultat explicite (retourne unJob).async: Lance une coroutine qui retourne un résultat sous forme deDeferred.
import kotlinx.coroutines.* suspend fun fetchData() = coroutineScope { // coroutineScope - constructeur pour la concurrence structurée val data1 = async { networkCall1() } // async retourne un Deferred val data2 = async { networkCall2() } // ... traitement des données après leur réception data1.await() // Obtenir le résultat de Deferred, suspend la coroutine jusqu'à ce qu'il soit terminé data2.await() } suspend fun networkCall1(): String { delay(1000) // Simulation d'une requête réseau return "Data 1" } suspend fun networkCall2(): String { delay(1500) return "Data 2" } fun startFetching() = runBlocking { // runBlocking - constructeur pour bloquer le thread actuel (pour main ou tests) launch { // launch retourne un Job println("Fetching data...") fetchData() println("Data fetched!") } } -
Distributeurs (Dispatchers) : Définissent sur quel thread ou pool de threads la coroutine sera exécutée.
Dispatchers.Default: Pour les tâches intensives en CPU.Dispatchers.IO: Pour les opérations d'E/S bloquantes (fichiers, réseau).Dispatchers.Main: Thread principal (seulement pour Android et Swing/JavaFX).Dispatchers.Unconfined: Lance la coroutine dans le thread qui l'a appelée, elle se suspend et reprend dans le thread qui l'a relancée.
import kotlinx.coroutines.* fun simpleTask() { GlobalScope.launch(Dispatchers.IO) { // Spécification du distributeur // Exécution d'une opération d'E/S println("Exécuté sur le thread : ${Thread.currentThread().name}") } } fun main() = runBlocking { launch(Dispatchers.Default) { println("Thread par défaut : ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Thread non confiné 1 : ${Thread.currentThread().name}") delay(100) // Suspension println("Thread non confiné 2 : ${Thread.currentThread().name}") // Reprise dans un autre thread (possiblement) } delay(200) // Attendre la fin des coroutines } -
Fonctions de suspension (Suspending functions) : Fonctions marquées avec le mot-clé
suspend, qui peuvent être suspendues et reprises sans bloquer le thread. Ne peuvent être appelées que depuis d'autres fonctions de suspension ou blocs de coroutines. -
Gestion de l'annulation et des exceptions : Les coroutines supportent l'annulation structurée et la propagation des exceptions.
- Annulation :
import kotlinx.coroutines.* fun cancellableTask() = GlobalScope.launch { try { repeat(1000) { i -> println("Travail $i ...") delay(100) // fonction de suspension respectant l'annulation } } catch (e: CancellationException) { println("Tâche annulée!") } finally { println("Nettoyage...") } } fun main() = runBlocking { val job = cancellableTask() delay(500) // Attendre un peu job.cancelAndJoin() // Annuler et attendre la fin } - Exceptions : En cas de
launch, une exception non capturée entraînera la chute de l'application (sur Android, par défaut). En cas deasync, l'exception sera levée lors de l'appel àawait(). Pour un contrôle plus granulaire, on utiliseCoroutineExceptionHandlerouSupervisorJob.
import kotlinx.coroutines.* fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("Exception capturée : $exception") } val job = GlobalScope.launch(handler) { // Application du gestionnaire throw IllegalStateException("Quelque chose a mal tourné") } job.join() // Attendre la fin } - Annulation :