53 - Corrutinas: Flujos (Flow)

Un flujo es un tipo de corrutina que puede emitir varios valores de manera secuencial, en lugar de las funciones de suspensión que pueden retornar un único valor.

Un flujo conceptualmente es una transmisión de datos que se puede efectuar de forma asíncrona.

Los valores emitidos deben ser del mismo tipo. Por ejemplo, un Flow es un flujo que emite valores enteros, pero pueden ser de cualquier otro tipo: String, Float, un data class Persona etc.

Un flujo puede enviar de forma segura una solicitud de red para producir el siguiente valor sin bloquear el subproceso principal de la aplicación y evitar su bloqueo.

Veamos como administrar un flujo mediante el API de Flow:

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

data class Persona(val nombre: String, val edad: Int)


fun retornarPersona(): Flow<Persona> = flow {
    val lista = listOf(
        Persona("diego", 53),
        Persona("juan", 33),
        Persona("ana", 33)
    )
    for (elemento in lista) {
        delay(1000)
        emit(elemento)
    }
}

fun main() = runBlocking {
    retornarPersona().collect { persona -> println("${persona.nombre} ${persona.edad}") }
}
Coroutines runBlocking Flow

Flow es una interface y mediante la llamada a la función flow pasamos una función lambda donde mediante la llamada de la función emit retornamos el dato que será procesado desde la llamada a la función collect.

Como collect es una función de suspensión, la misma debe llamarse desde un bloque de una corrutina, en nuestro caso dentro de runBlocking.

Podemos imaginar la recuperación de datos de personas que se encuentran en un servidor que requiere un tiempo no trivial.

Podemos hacer la llamada a la función 'retornarPersona' en forma asíncrona para seguir con la ejecución del hilo principal del programa y no tener que esperar la recuperación de todos los datos:

import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*

data class Persona(val nombre: String, val edad: Int)


fun retornarPersona(): Flow<Persona> = flow {
    val lista = listOf(
        Persona("diego", 53),
        Persona("juan", 33),
        Persona("ana", 33)
    )
    for (elemento in lista) {
        delay(1000)
        emit(elemento)
    }
}

fun main() = runBlocking {
    async { retornarPersona().collect { persona -> println("${persona.nombre} ${persona.edad}") }}
    println("Fin de la main")
}