Kotlin Coroutine : Rx & Dispatchers

Ici je ne vais pas comparer RX et les coroutines, je ne suis pas une personne réferente sur les deux sujets et n’est donc pas l’autorité pour le faire.
Dans cet article je vais surtout parler de la manière de marier les deux librairies afin de déléguer la partie asynchrone de Rx au Coroutine.

D’un point de vu personnel, je trouve les coroutines plus simple à aborder que Rx (pour le côté asynchrone)

Dispatchers, ils sont le moyen de preciser le context ou va tourner l’execution des coroutines. Il y a les dispatchers de base mais il est aussi possible d’en créer soi même. Notamment en se basant sur les executor de Rx.
Par exemple :

val schedulersIODispatcher = Schedulers.io().asCoroutineDispatcher()

Pour faire appel à asCoroutineDispatcher il faudra rajouter
implementation « org.jetbrains.kotlinx:kotlinx-coroutines-rx2:X.X.X »
A votre projet.

C’est tout simple, avec asCoroutineDispatcher() on va convertir l’instance d’un executor en une implementation de CoroutineDispatcher (pour citer la documentation).
Pour utiliser ce dispatcher par exemple sur un launch il faudra faire comme ceci :

launch(schedulersIODispatcher) {}

Ce qu’on vient de faire, c’est remplacer le subscribeOn.
Maintenant faisons de même avec l’observeOn. Généralement on le fait tourner dans l’AndroidSchedulers.mainThread(). Etant donné que c’est l’UI thread, il va falloir switcher de context la coroutine.

withContext(UI) {}

Avec withContext, on peut changer de context tout en restant dans le launch. Le launch est ici avec un context SchedulersIO, le withContext avec l’UI, l’inverse ou d’autres compositions sont aussi possible, l’intérêt est de ne pas avoir à recréer une coroutine.
Il faudra aussi donner un context à witchContext, nous allons continuer de reprendre l’executor de Rx, cependant cette fois nous devront créer un dispatcher basé sur AndroidSchedulers.mainThread()
Ca nous donne :

launch(schedulersIODispatcher) {

// une action dans le context IO
withContext(main) {

//une action dans le context UI/MainThread
}
}

Au lieu de créer à chaque fois des dispatchers custom, on va déléguer à une autre classe. On va reprendre les recommendations de Chris Banes pour ce sujet et créer un objet qui sera en charge d’injecter les dispatchers.

En premier nous créons de quoi injecter les Exécutors Rx.

data class AppRxSchedulers(
val database: Scheduler,
val disk: Scheduler,
val network: Scheduler,
val main: Scheduler
)
@Singleton
@Provides
fun provideRxSchedulers() = AppRxSchedulers(
database = Schedulers.single(),
disk = Schedulers.io(),
network = Schedulers.io(),
main = AndroidSchedulers.mainThread()
)

Ensuite nous créons les Dispatchers qui vont se servir de la classe précédente.

data class AppCoroutineDispatchers(
val database: CoroutineDispatcher,
val disk: CoroutineDispatcher,
val network: CoroutineDispatcher,
val main: CoroutineDispatcher
)
@Singleton
@Provides
fun provideDispatchers(schedulers: AppRxSchedulers) =
AppCoroutineDispatchers(
database = schedulers.database.asCoroutineDispatcher(),
disk = schedulers.disk.asCoroutineDispatcher(),
network = schedulers.network.asCoroutineDispatcher(),
main = AndroidSchedulers.mainThread().asCoroutineDispatcher()
)

Voila vous savez comment créer des Dispatchers pour des coroutines en utilisant les Exécuteurs de Rx.