Middle
¿Cómo se pueden cambiar los hilos en Flow? ¿En qué hilo funciona Flow?
sobes.tech AI
Respuesta de la IA
Por defecto, Flow funciona en el hilo desde el cual fue iniciado. Puedes cambiar de hilo usando el operador flowOn.
import kotlinx.coroutines.CoroutineDispatcher // Para CoroutineDispatcher
import kotlinx.coroutines.Dispatchers // Para Dispatchers
import kotlinx.coroutines.flow.Flow // Para Flow
import kotlinx.coroutines.flow.flow // Para flow
import kotlinx.coroutines.flow.flowOn // Para flowOn
import kotlinx.coroutines.runBlocking // Para runBlocking
// Ejemplo de función que devuelve un Flow
fun simpleFlow(): Flow<Int> = flow {
logThread("Flow iniciado") // Registro del hilo donde se inicia el builder de flow
for (i in 1..3) {
emit(i) // Emitimos valores
}
}
fun main() = runBlocking {
simpleFlow()
.flowOn(Dispatchers.IO) // Cambiamos upstream (emitores) a Dispatchers.IO
.collect { value ->
logThread("Recogido $value") // Registro del hilo donde se recogen los valores
}
}
// Función auxiliar para registrar el hilo
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
El operador flowOn afecta al hilo en el que se ejecutan los operadores antes de él en la cadena (incluyendo el flow builder). Los operadores después de flowOn se ejecutan en el hilo especificado en el argumento flowOn. Si hay varios flowOn en la cadena, cada uno afecta a la parte de la cadena antes de él.
Ejemplo con múltiples flowOn:
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.runBlocking
fun simpleFlowWithMultipleFlowOn(): Flow<String> = flow {
logThread("Builder de Flow iniciado") // Funcionará en el primer flowOn especificado
emit("A")
emit("B")
}.map {
logThread("Mapeo $it") // Funcionará en el segundo flowOn especificado
it.toLowerCase()
}.flowOn(Dispatchers.Default) // El segundo flowOn afecta a map() y al builder de flow
.filter {
logThread("Filtrando $it") // Funcionará en el hilo donde se llama a collect (por defecto main/runBlocking)
true
}.flowOn(Dispatchers.IO) // El primer flowOn afecta a map() y al builder de flow
fun main() = runBlocking {
simpleFlowWithMultipleFlowOn().collect { value ->
logThread("Recogiendo $value") // Funciona en el hilo runBlocking (main)
}
}
fun logThread(msg: String) {
println("[$msg] [${Thread.currentThread().name}]")
}
En este ejemplo:
- El builder de
flowymapfuncionarán enDispatchers.Default(porque es el últimoflowOnen la cadena antes de ellos). filterfuncionará en el hilo desde el cual se llama acollect, es decir, en el hilo donde se ejecutarunBlocking(normalmente Main en Android).
Es importante entender que flowOn crea un buffer intermedio y no es un "cambio transparente" de hilo.