Middle
Comment peut-on basculer entre les threads dans Flow ? Sur quel thread Flow fonctionne-t-il ?
sobes.tech IA
Réponse de l'IA
Par défaut, Flow fonctionne sur le thread à partir duquel il a été lancé. Vous pouvez changer de thread en utilisant l'opérateur flowOn.
import kotlinx.coroutines.CoroutineDispatcher // Pour CoroutineDispatcher
import kotlinx.coroutines.Dispatchers // Pour Dispatchers
import kotlinx.coroutines.flow.Flow // Pour Flow
import kotlinx.coroutines.flow.flow // Pour flow
import kotlinx.coroutines.flow.flowOn // Pour flowOn
import kotlinx.coroutines.runBlocking // Pour runBlocking
// Exemple de fonction renvoyant un Flow
fun simpleFlow(): Flow<Int> = flow {
logThread("Flow démarré") // Journalisation du thread où le builder de flow est lancé
for (i in 1..3) {
emit(i) // Émission des valeurs
}
}
fun main() = runBlocking {
simpleFlow()
.flowOn(Dispatchers.IO) // Change upstream (émiteurs) vers Dispatchers.IO
.collect { value ->
logThread("Collecté $value") // Journalisation du thread où les valeurs sont collectées
}
}
// Fonction auxiliaire pour journaliser le thread
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
L'opérateur flowOn influence le thread sur lequel s'exécutent les opérateurs avant lui dans la chaîne (y compris le flow builder). Les opérateurs après flowOn s'exécutent sur le thread spécifié dans l'argument flowOn. Si plusieurs flowOn sont présents dans la chaîne, chacun influence la partie de la chaîne qui le précède.
Exemple avec plusieurs flowOn:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
fun simpleFlowWithMultipleFlowOn(): Flow<String> = flow {
logThread("Builder de Flow démarré") // Fonctionne sur le premier flowOn spécifié
emit("A")
emit("B")
}.map {
logThread("Mapping $it") // Fonctionne sur le deuxième flowOn spécifié
it.toLowerCase()
}.flowOn(Dispatchers.Default) // Le deuxième flowOn influence map() et le builder de flow
.filter {
logThread("Filtrage $it") // Fonctionne sur le thread où est appelé collect (par défaut main/runBlocking)
true
}.flowOn(Dispatchers.IO) // Le premier flowOn influence map() et le builder de flow
fun main() = runBlocking {
simpleFlowWithMultipleFlowOn().collect { value ->
logThread("Collecte $value") // Fonctionne sur le thread runBlocking (main)
}
}
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
Dans cet exemple :
- Le
flowbuilder etmapfonctionneront surDispatchers.Default(car c'est le dernierflowOndans la chaîne avant eux). filterfonctionnera sur le thread depuis lequelcollectest appelé, c'est-à-dire sur le thread où s'exécuterunBlocking(habituellement Main en Android).
Il est important de comprendre que flowOn crée un buffer intermédiaire et ne constitue pas un "changement de thread transparent".