Les coroutines en Kotlin sont des threads légers avec prise en charge de la suspension et de la reprise des calculs sans bloquer les threads du système d'exploitation. Elles sont lancées via des fonctions comme launch, async en présence d'un CoroutineScope parent.
La répartition se fait via des objets CoroutineDispatcher, qui déterminent dans quel thread/exécuteur la coroutine s'exécute (Dispatchers.Main, Dispatchers.IO, Dispatchers.Default).
Exemple :
fun main() = runBlocking { launch(Dispatchers.IO) { val data = getDataFromNetwork() withContext(Dispatchers.Main) { updateUI(data) } } }
Annulation : Les coroutines sont annulées par l'annulation de leur job/Scope, ce qui lance une exception interne CancellationException. Les coroutines doivent vérifier périodiquement le drapeau d'annulation ou appeler des fonctions suspendantes pour se terminer correctement.
Gestion des erreurs : Les exceptions dans les coroutines peuvent "couler" - par exemple, si vous ne gérez pas l'erreur dans une coroutine enfant, elle terminera seulement son travail, et le parent ne sera pas informé du problème. Pour cela, il existe des mécanismes tels que SupervisorJob et CoroutineExceptionHandler.
Nuances du passage de contexte :
Que se passe-t-il si, à l'intérieur d'une coroutine parent, l'une des enfants se termine avec une erreur alors que les autres continuent de travailler ? Toutes les enfants seront-elles annulées ?
_ Beaucoup croient à tort que l'erreur "reste dans l'enfant"._
Réponse correcte : Si un Job normal (ou launch) est utilisé, toutes les coroutines enfants sont automatiquement annulées lorsque l'une d'entre elles rencontre une erreur. Pour que les coroutines enfants ne soient pas annulées, on utilise SupervisorJob ou supervisorScope :
supervisorScope { launch { error("echec") } launch { println("Ce code fonctionnera") } }
Histoire
Mauvaise gestion des erreurs - effondrement du flux : Dans le projet, des coroutines ont été utilisées pour charger des données. Les exceptions "coulaient" dans les coroutines enfants, ce qui rendait le niveau de retry/recovery inopérant, et l'écran principal restait vide sans aucun message d'erreur pour l'utilisateur.
Histoire
Gel de l'UI en raison du travail avec Dispatchers.Main : Un jeune développeur Android a lancé une tâche de calcul lourde sur Dispatchers.Main - l'UI a commencé à "geler". Il n'y avait pas de compréhension que tous les calculs lourds doivent être exécutés sur Dispatchers.Default ou Dispatchers.IO.
Histoire
AbortError lors de l'annulation du scope parent : Un des développeurs n'a pas réalisé qu'à l'annulation du scope parent, toutes les coroutines enfants se terminent par une annulation, et une opération critique (sauvegarde de données) n'a pas été finalisée.