Comment lancer une coroutine
Dans l' kotlinx.coroutines
bibliothèque, vous pouvez commencer à nouveau coroutine en utilisant soit launch
ou async
fonction.
Sur le plan conceptuel, async
est juste comme launch
. Il démarre une nouvelle coroutine qui est un poids léger fil qui fonctionne simultanément avec toutes les autres coroutines.
La différence est que le lancement renvoie une Job
et n'a aucune valeur, alors que async
renvoie un Deferred
- un peu de poids non-blocage de l'avenir que représente une promesse de fournir un résultat ultérieurement. Vous pouvez utiliser .await()
sur un différés à la valeur d'obtenir son résultat final, mais Deferred
est aussi un Job
, de sorte que vous pouvez l'annuler si nécessaire.
Coroutine contexte
Dans Android, nous avons l'habitude d'utiliser deux contexte:
-
uiContext
à l'expédition d'exécution sur l'Android principale UI
fil (pour le parent coroutine).
-
bgContext
à l'expédition d'exécution dans le thread d'arrière-plan (pour l'enfant coroutines).
Exemple
//dispatches execution onto the Android main UI thread
private val uiContext: CoroutineContext = UI
//represents a common pool of shared threads as the coroutine dispatcher
private val bgContext: CoroutineContext = CommonPool
Dans l'exemple suivant, nous allons utiliser CommonPool
pour bgContext
qui limite le nombre de threads en parallèle, la valeur de Runtime.getRuntime.availableProcessors()-1
. Donc, si la coroutine tâche est planifiée, mais tous les cœurs sont occupés, il sera mis en file d'attente.
Vous pouvez envisager d'utiliser newFixedThreadPoolContext
ou votre propre mise en œuvre de la mise en cache du pool de threads.
lancement + async (exécution de la tâche)
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
val task = async(bgContext) { dataProvider.loadData("Task") }
val result = task.await() // non ui thread, suspend until finished
view.showData(result) // ui thread
}
lancement + async + async (exécuter deux tâches de manière séquentielle)
Remarque: task1 et task2 sont exécutées de manière séquentielle.
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
// non ui thread, suspend until task is finished
val result1 = async(bgContext) { dataProvider.loadData("Task 1") }.await()
// non ui thread, suspend until task is finished
val result2 = async(bgContext) { dataProvider.loadData("Task 2") }.await()
val result = "$result1 $result2" // ui thread
view.showData(result) // ui thread
}
lancement + async + async (exécuter deux tâches en parallèle)
Remarque: task1 et task2 sont exécutés en parallèle.
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
val task1 = async(bgContext) { dataProvider.loadData("Task 1") }
val task2 = async(bgContext) { dataProvider.loadData("Task 2") }
val result = "${task1.await()} ${task2.await()}" // non ui thread, suspend until finished
view.showData(result) // ui thread
}
Comment faire pour annuler une coroutine
La fonction loadData
renvoie un Job
objet qui peut être annulée. Lorsque le parent coroutine est annulé, tous ses enfants sont récursivement annulé, trop.
Si l' stopPresenting
fonction a été appelée lors de l' dataProvider.loadData
était encore en cours, la fonction view.showData
ne sera jamais appelé.
var job: Job? = null
fun startPresenting() {
job = loadData()
}
fun stopPresenting() {
job?.cancel()
}
private fun loadData() = launch(uiContext) {
view.showLoading() // ui thread
val task = async(bgContext) { dataProvider.loadData("Task") }
val result = task.await() // non ui thread, suspend until finished
view.showData(result) // ui thread
}
La réponse complète est disponible dans mon article Android Coroutine Recettes