Dispatchers.Main.immediate et Dispatchers.Unconfined : comprendre ces deux dispatchers “spéciaux”
En Kotlin coroutines, un dispatcher décide où et comment une coroutine s’exécute (sur quel thread, à quel moment).
Les dispatchers les plus connus sont :
Dispatchers.Main(UI / thread principal)Dispatchers.IO(IO, réseau, disque)Dispatchers.Default(calculs CPU)
Mais il existe aussi deux dispatchers plus particuliers, souvent mal compris :
- Dispatchers.Main.immediate
- Dispatchers.Unconfined
Ils ne servent pas à “faire mieux” ou “aller plus vite”, mais à gérer des cas très précis de synchronisation et d’ordonnancement.
1) Rappel rapide : que fait un dispatcher ?
Quand tu écris :
withContext(Dispatchers.Main) {
updateUi()
}
Tu demandes au runtime :
- de s’assurer que le code s’exécute sur le thread principal,
- en le planifiant si nécessaire.
Le dispatcher décide s’il faut :
- changer de thread,
- poster une tâche,
- ou exécuter immédiatement.
2) Dispatchers.Main.immediate : “si je suis déjà sur le Main, exécute tout de suite”
Dispatchers.Main.immediate est une variante de Dispatchers.Main.
Son comportement est simple :
- si tu es déjà sur le thread principal ? exécution immédiate,
- sinon ? planification normale sur le Main thread.
2.1 Différence avec Dispatchers.Main
Dispatchers.Main :
- poste toujours le travail dans la queue du Main thread,
- même si tu es déjà sur le Main.
Dispatchers.Main.immediate :
- évite ce “détour” si possible,
- réduit les changements de contexte inutiles.
2.2 Exemple concret
suspend fun update() {
withContext(Dispatchers.Main.immediate) {
// Si on est déjà sur le Main thread,
// ce code s'exécute immédiatement
render()
}
}
Cela permet d’éviter des effets indésirables comme :
- un rendu UI retardé,
- des animations qui “sautent” une frame,
- des appels imbriqués inutilement re-postés.
2.3 Cas d’usage typiques
- Mise à jour UI depuis du code déjà sur le Main.
- Architectures MVI / MVVM avec beaucoup d’allers-retours UI.
- Éviter des clignotements ou délais visuels.
Sur Android, Main.immediate est souvent utilisé dans les frameworks UI
et les ViewModels avancés.
3) Dispatchers.Unconfined : “je m’exécute là où je peux, jusqu’à suspension”
Dispatchers.Unconfined est très différent.
Il signifie littéralement :
“Je ne suis pas attaché à un thread précis.”
Son comportement :
- la coroutine démarre dans le thread courant,
- après une suspension, elle reprend dans n’importe quel thread approprié.
3.1 Exemple simple
launch(Dispatchers.Unconfined) {
println(Thread.currentThread().name)
delay(100)
println(Thread.currentThread().name)
}
Résultat possible :
- avant
delay? thread appelant, - après
delay? thread du scheduler interne.
? Le thread peut changer, et ce n’est pas prévisible.
4) Pourquoi Dispatchers.Unconfined existe ?
Dispatchers.Unconfined n’est pas conçu pour du code applicatif classique.
Il est surtout utile pour :
- des tests,
- du code bas niveau de librairie,
- éviter une dépendance forte à un dispatcher précis.
Il permet à une coroutine de :
- démarrer immédiatement,
- laisser le runtime décider ensuite où reprendre.
5) Pourquoi Dispatchers.Unconfined est dangereux en pratique
En code applicatif (surtout Android), Unconfined est souvent une mauvaise idée.
Problèmes courants :
- exécution sur le mauvais thread (UI thread violé),
- comportement difficile à raisonner,
- bugs dépendants du timing,
- code difficile à maintenir.
Exemple problématique :
launch(Dispatchers.Unconfined) {
textView.text = "Hello" // peut crasher si pas sur Main
}
Ce code peut fonctionner… ou non. C’est précisément le problème.
6) Main.immediate vs Unconfined : différence essentielle
Même s’ils peuvent sembler similaires (“exécution immédiate”), leur intention est très différente :
- Main.immediate :
- reste attaché au Main thread,
- optimise l’ordonnancement,
- sécurisé pour l’UI.
- Unconfined :
- pas attaché à un thread,
- comportement variable après suspension,
- à éviter pour l’UI.
7) Règles simples à retenir
- Pour l’UI Android ? Dispatchers.Main ou Main.immediate.
- Pour optimiser des appels déjà sur le Main ? Main.immediate.
- Pour le code métier classique ? Default ou IO.
- Éviter Dispatchers.Unconfined en code applicatif.
Conclusion
Dispatchers.Main.immediate est une optimisation contrôlée du Main dispatcher :
il évite des re-posts inutiles tout en restant sûr pour l’UI.
Dispatchers.Unconfined, lui, est un outil bas niveau,
utile dans des contextes spécifiques (tests, librairies),
mais rarement adapté au code applicatif quotidien.
En pratique :
- Main.immediate ? oui, avec intention.
- Unconfined ? seulement si tu sais exactement pourquoi.