ProgrammationKotlin Software Engineer

Comment fonctionnent les coroutines en Kotlin ? Décrivez le mécanisme de lancement, la répartition, l'annulation et le traitement des erreurs. Donnez un exemple d'utilisation et expliquez les nuances liées au passage du contexte et aux exceptions.

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse

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 :

  • Le contexte (par exemple, Job, Dispatcher, éléments personnalisés) est hérité lors de la création de nouvelles coroutines.
  • On ne peut pas simplement passer des paramètres entre des scopes s'ils sont fermés ou annulés.

Question piège

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") } }

Exemples d'erreurs réelles dues à une mauvaise compréhension des subtilités du sujet


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.