Comment remplacer AsyncTask par les coroutines de Kotlin

Utilisez-vous toujours AsyncTask dans vos applications Android? Vous ne devriez probablement plus l'être. Voici comment les remplacer par les Coroutines de Kotlin.

Pendant très longtemps sous Android, si vous deviez faire quelque chose de manière asynchrone lors de la création d'une application, vous utiliseriez probablement AsyncTask. AsyncTask est une API dans le framework Android qui facilite (ish) l'exécution d'opérations en arrière-plan et renvoie des valeurs une fois terminées. Et cela a du sens. Contrairement aux Coroutines de Kotlin, AsyncTask existe depuis un certain temps et est directement intégré.

Cependant, la philosophie de conception et la mise en œuvre d'AsyncTask sont devenues quelque peu obsolètes au fil des ans. Pour cette raison, Google a obsolète l'API AsyncTask. Vous pouvez toujours l'utiliser si vous le souhaitez, mais Google ne vous le recommande pas. Heureusement, il existe de nombreuses alternatives à AsyncTask, y compris une fonctionnalité du langage Kotlin: les coroutines.

L'API coroutines de Kotlin est un framework incroyablement puissant qui vous permet de faire tout un tas de choses. Cet article ne fera qu’effleurer la surface de ce qui est possible. Nous passerons en revue les bases nécessaires pour migrer d'AsyncTask vers les coroutines.

Ajout de la prise en charge des coroutines

Avant de pouvoir commencer à utiliser des coroutines, vous devez les ajouter à votre projet.

Ajout de la prise en charge de Kotlin

Si Kotlin est déjà implémenté, passez à la section suivante. Sinon, vous devrez ajouter le support Kotlin à votre projet. Consultez mon tutoriel sur l'ajout de Kotlin à un projet existant pour plus de détails.

Ajout de bibliothèques de coroutines

Au niveau de votre module build.gradle, incluez les dépendances suivantes.

dependencies {
...
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-core: 1.5.0'
implementation 'org.jetbrains.kotlinx: kotlinx-coroutines-android: 1.5.0'
}

Synchronisez votre projet et les coroutines de Kotlin seront désormais disponibles.

Utiliser des coroutines

Implémentation d'un CoroutineScope

Pour utiliser des coroutines, vous devez disposer d'une instance CoroutineScope. Un moyen simple de procéder consiste simplement à l’implémenter dans votre classe conteneur.

Par exemple, pour implémenter un CoroutineScope dans une activité :

classSomeActivity : AppCompatActivity, CoroutineScope by MainScope() {
...

override fun onDestroy(){
super.onDestroy()

cancel()
}
}

Cela permettra à SomeActivity d'implémenter l'interface CoroutineScope via la classe MainScope. MainScope gérera toute la logique d'implémentation de CoroutineScope, tout en vous permettant d'utiliser les méthodes CoroutineScope. Appel cancel() dans onDestroy() s'assure qu'aucune logique asynchrone ne continue de s'exécuter après la sortie de l'activité.

Remplacement d'AsyncTask par des Coroutines

Supposons que vous ayez une AsyncTask dans une activité qui effectue une opération de longue durée en arrière-plan et renvoie finalement une chaîne. Quelque chose comme ce qui suit.

private inner classSomeTask : AsyncTask() {
override fun doInBackground(vararg params: Void): String {
try {
//Pretend this is an actual operation that takes 10 seconds and not just sleeping.
Thread.sleep(10000);
} catch (e: InterruptedException) {}

return"SomeString";
}

override fun onPostExecute(result: String) {
val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

Le remplacer par une coroutine est facile. Utilisez simplement le async() méthode. Kotlin async() s'exécute sur le thread sur lequel il a été lancé, mais de manière asynchrone. Cela signifie que vous pouvez mettre à jour les vues et autres sans avoir à vous soucier d'utiliser le bon fil de discussion.

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...

private fun doOperation(){
async {
//Inside coroutine scopes (like inside async here), delay is used instead of Thread.sleep.
delay(10000)

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = "SomeString"
}
}
}

Comme vous pouvez le constater, utiliser des coroutines peut être beaucoup plus simple que d'utiliser AsyncTask. Vous n'êtes pas obligé d'appeler async() et laissez-le faire son travail, cependant. Vous pouvez y faire référence et même attendre qu'il se termine.

val asyncJob = async {
//Some operation
}
//Pause here until the async block is finished.
asyncJob.await()

//This won't run until asyncJob finishes, but other operations started before the job, or started from another method, can still run.
doSomethingElse()

Renvoyer des valeurs avec async

Vous pouvez même renvoyer une valeur de async() si tu veux. L’exemple original pourrait donc ressembler à ceci.

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...
private fun doOperation(){
val asyncJob = async {
//Inside coroutine scopes (like inside async here), delay is used instead of Thread.sleep.
delay(10000)

//Whatever the type is of the last line is what async() eventually returns.
"SomeString"
}

val result = asyncJob.await()

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

Utilisation de withContext

Pour plus de commodité, Kotlin fournit withContext(). Cela intègre l'ensemble await() chose et vous renvoie simplement la valeur.

classSomeActivity : AppCompatActivity(), CoroutineScope by MainScope() {
...
private fun doOperation(){
//Run asynchronously on the main Thread.
val result = withContext(Dispatchers.Main) {
delay(10000)

"SomeResult"
}

val someTextView = findViewById(R.id.some_text_view)
someTextView.text = result
}
}

Conclusion

Les exemples ci-dessus ne sont que quelques utilisations de base des coroutines de Kotlin pour vous aider à démarrer. Vous n'êtes pas obligé de limiter les coroutines aux activités ou même à tout ce qui a un cycle de vie approprié. Vous pouvez les exécuter pratiquement n’importe où. Il existe également des opérations plus avancées, comme choisir quel thread doit exécuter la logique asynchrone. Ce guide sert principalement à montrer comment remplacer une simple AsyncTask par une simple coroutine.

Pour plus de détails sur le fonctionnement des coroutines et sur la façon dont vous pouvez utiliser leurs fonctionnalités plus avancées, consultez le documentation officielle de Kotlin.