Kotlin Flow es una nueva API de procesamiento de flujo desarrollada por JetBrains, la empresa detrás del idioma Kotlin. Es una implementación del Especificación de flujo reactivo, una iniciativa cuyo objetivo es proporcionar un estándar para el procesamiento de flujos asincrónicos. Jetbrains construyó Kotlin Flow sobre Corutinas de Kotlin.
Al usar Flow para manejar flujos de valores, puede transformar datos en formas complejas de múltiples subprocesos, ¡escribiendo solo un pequeño fragmento de código!
En este tutorial, tendrás la oportunidad de jugar con varios enfoques diferentes para manejar colecciones y explorarás las capacidades de Kotlin Flow mediante la creación de una aplicación meteorológica simple. En el proceso, aprenderá sobre:
- Recopilaciones y flujos de datos.
- Llamadas a API sincrónicas y asincrónicas.
- Flujos de datos fríos y calientes.
- Manejo de excepciones durante el procesamiento de flujo.
También debe tener un conocimiento básico de Corutinas de Kotlin para seguir junto con este tutorial. Puede consultar estos tutoriales para familiarizarse con Coroutines:
La aplicación de muestra en este tutorial usa el patrón arquitectónico MVVM. MVVM significa Model-View-ViewModel y representa un patrón en el que se actualiza la interfaz de usuario a través de flujos reactivos de datos. Si no está familiarizado con este patrón, consulte nuestro MVVM en Android curso en video para familiarizarse con él.
Cómo Empezar
En la primera parte del tutorial, aprenderá sobre los conceptos de Kotlin Flow, utilizando la aplicación Kotlin Playground como ... bueno, ¡un patio de recreo! Luego, usará lo que ha aprendido para desarrollar una aplicación de Android más sólida que muestre los datos recuperados a través de llamadas a la API.
Descargue los materiales para este tutorial usando el Descargar materiales en la parte superior o inferior de la página. Por ahora, abra el Parque infantil-Starter proyecto en Estudio Android. Este es solo un proyecto vacío que servirá como patio de recreo.
Devolver varios valores
Usted probablemente sabe eso suspender funciones puede devolver un único valor de forma asincrónica. Al usar funciones de suspensión, no tiene que preocuparse por el enhebrado, ¡la API de Coroutines lo hace por usted!
Flujo, sin embargo, puede volver múltiples valores de forma asincrónica y en el tiempo. Operaciones asincrónicas son operaciones que debe esperar, como solicitudes de red. ¡Nunca se sabe cuánto tiempo pueden llevar estas operaciones! Pueden tardar desde un par de milisegundos hasta varios segundos en obtener una respuesta. Cualquier operación de larga duración debe ser asíncrona porque esperarlos activamente puede congelar sus programas.
Verá cómo devolver valores usando funciones de suspensión es muy diferente de la API de Flow, ¡con algunos ejemplos!
Lista
Abierto principal.kt archivo y agregue la siguiente función:
suspender diversión getValues (): Lista {delay (1000) return listOf (1, 2, 3)}
Esta función calcula valores y agrega esos valores en un List
. delay()
simula una operación de larga duración, como lo haría con una API remota.
Ahora agregue una función para procesar estos valores:
fun processValues () {runBlocking {val values = getValues () for (value in values) {println (value)}}}
Llamar processValues()
en main()
:
fun main () {processValues ()}
Genere y ejecute el código, usando el ícono verde "reproducir" al lado de la función principal. Obtendrá esta salida después de un retraso de un segundo:
1 2 3
Cuando usted llama getValues()
, devuelve un List
con tres valores. Luego usa esos valores en processValues()
. Dentro de una for
bucle, iteras sobre el List
e imprima los valores.
Una representación visual de la función es la siguiente:
Esto está bien para tres valores. Pero no si se necesita mucho tiempo para calcular estos valores. En ese caso, tendrías que esperar todos de los valores a calcular. Si cada valor toma un segundo, ¡esperaría horas por miles de valores!
Es muy ineficiente ya que agrega un retraso adicional al procesamiento de datos. Idealmente, desea comenzar a procesar cada elemento de la lista tan pronto como esté disponible. Secuencias permitirle hacer esto.
Secuencia
Las secuencias son muy similares a las listas. Pero a diferencia de las listas, son evaluado perezosamente. Esto significa que producen valores a medida que los itera, en lugar de producirlos todos a la vez. Refactor getValues()
para devolver un Sequence
:
suspender diversión getValues (): Secuencia = secuencia {Thread.sleep (250) yield (1) Thread.sleep (250) yield (2) Thread.sleep (250) yield (3)}
Thread.sleep(250)
simula un retraso al calcular cada valor.
Construya y ejecute el proyecto. Obtendrá el mismo resultado que antes, pero esta vez no tendrá que esperar todos los valores. Los producirá y consumirá, uno a la vez:
1 2 3
Ahora, en lugar de esperar todos los elementos, processValues()
consume cada artículo como getValues()
lo produce.
Uso de secuencias Iterator
s debajo del capó y bloquee mientras espera el siguiente elemento. Esto funciona cuando se devuelve una lista simple, pero ¿qué sucede si su aplicación necesita comunicarse con un API de transmisión?
Channel
Las API de transmisión son casi exactamente lo contrario de las API REST. Cuando se comunica con una API REST, realiza una solicitud y la API envía una respuesta. Una API de transmisión funciona de manera diferente. Se conecta a un cliente y escucha continuamente nueva información a lo largo del tiempo. Twitter, por ejemplo, proporciona una API de transmisión que puede utilizar para transmitir tweets en tiempo real.
Puedes usar Sequence
s para flujos síncronos. Pero necesita una solución diferente para transmisiones asincrónicas.
Para transmisiones asincrónicas, puede usar Channel
s de Kotlin Coroutines. Conceptualmente, puede pensar en los canales como tuberías. Envía artículos a través de un conducto y recibe una respuesta a través del otro. Sin embargo, un canal representa un calientes flujo de valores. Una vez más, las corrientes calientes comienzan a producir valores de inmediato.
Y esto introduce otro conjunto de desafíos.
Corrientes calientes versus corrientes frías
Un canal, que es un flujo caliente, producirá valores incluso si no los está escuchando en el otro lado. Y si no está escuchando la transmisión, está perdiendo valores.
En el siguiente diagrama, getValues()
emite los elementos a través de un canal. processValues()
recibe 1, 2, 3y luego deja de escuchar elementos. El canal sigue produciendo los elementos, incluso cuando nadie está escuchando:
En la práctica, puede utilizar un canal para tener una conexión de red abierta. Pero eso puede provocar pérdidas de memoria. O podría olvidarse de suscribirse a un canal y "perder" valores.
Los flujos calientes impulsan los valores incluso cuando nadie los consume. Sin embargo, corrientes frías, comience a impulsar valores solo cuando comience a recolectar!
Y Flujo de Kotlin es una implementación de cold streams, impulsada por Kotlin Coroutines.
Conceptos básicos de Kotlin Flow
El flujo es un flujo que produce valores de forma asincrónica. Además, Flow usa corrutinas internamente. Y debido a esto, disfruta de todas las ventajas de concurrencia estructurada.
Con la concurrencia estructurada, las corrutinas viven durante un período de tiempo limitado. Esta vez está conectado al CoroutineScope
inicias tus corrutinas en.
Cuando cancela el alcance, también libera las corrutinas en ejecución. Las mismas reglas se aplican también a Kotlin Flow. Cuando cancela el alcance, también se deshace del flujo. ¡No tienes que liberar memoria manualmente! :]
Existen algunas similitudes entre Kotlin Flow, LiveData y RxJava. Todos ellos proporcionan una forma de implementar el patrón de observador en su código.
- Datos en tiempo real es un simple contenedor de datos observables. Se usa mejor para almacenar el estado de la interfaz de usuario, como listas de elementos. Es fácil de aprender y trabajar. Pero no proporciona mucho más que eso.
- RxJava es una herramienta muy poderosa para flujos reactivos. Tiene muchas características y una gran cantidad de operadores de transformación. ¡Pero tiene una curva de aprendizaje empinada!
- Flujo cae en algún lugar entre LiveData y RxJava. ¡Es muy potente pero también muy fácil de usar! ¡La API de Flow incluso se parece mucho a RxJava!
Tanto Kotlin Flow como RxJava son implementaciones del Especificación de flujo reactivo.
Sin embargo, Flow usa corrutinas internamente y no tiene algunas de las características que tiene RxJava. En parte porque no necesita algunas funciones, y en parte porque algunas funciones aún se están desarrollando.
Note: En la versión 1.3.0 de Kotlin, las API principales de Flow y los operadores básicos son estables. Las API que no son estables tienen anotaciones. @ExperimentalCoroutinesApi
or @FlowPreview
.
Ahora que ya tienes suficiente teoría, ¡es hora de crear tu primer Flow!
Constructores de flujo
Navegue hasta principal.kt en el proyecto de inicio.
Comenzará creando un flujo simple. Para crear un flujo, debe utilizar un generador de flujo. Comenzará utilizando el constructor más básico: flow { ... }
. Agregue el siguiente código arriba main()
:
val namesFlow = flow {val names = listOf ("Jody", "Steve", "Lance", "Joe") para (nombre en nombres) {retraso (100) emitir (nombre)}}
Asegúrese de agregar las importaciones del kotlinx.coroutines
paquete.
Aquí, estás usando flow()
para crear un flujo a partir de un bloque lambda suspendible. Dentro del bloque, declaras names
y asignarlo a una lista de nombres.
A continuación, usó un for
loop para revisar la lista de nombres y emitir cada nombre después de un pequeño retraso. El flujo utiliza emit()
enviar valores a los consumidores.
Hay otros constructores de Flow que puede utilizar para una declaración de Flow sencilla. Por ejemplo, puede utilizar flowOf()
para crear un flujo a partir de un conjunto fijo de valores:
val namesFlow = flowOf ("Jody", "Steve", "Lance", "Joe")
O puede convertir varias colecciones y secuencias en un flujo:
val namesFlow = listOf ("Jody", "Steve", "Lance", "Joe"). asFlow ()
Operadores de flujo
Además, puede utilizar operadores para transformar flujos, como haría con colecciones o secuencias. Hay dos tipos de operadores disponibles dentro del Flow: intermedio y terminal.
Operadores intermedios
Volver a la principal.kt y agregue el siguiente código a main()
:
fun main () = runBlocking {namesFlow .map {name -> name.length} .filter {length -> length <5} println ()}
Aquí, usó el Flujo de nombres de antes y le aplicó dos operadores intermedios:
-
map
transforma cada valor en otro valor. Aquí transformó los valores de los nombres a su longitud. -
filter
selecciona valores que cumplen una condición. Aquí eligió valores inferiores a cinco.
Lo importante a notar aquí es el bloque de código dentro de cada uno de estos operadores. ¡Estos bloques de código pueden llamar a funciones de suspensión! Entonces también puedes retrasar dentro de estos bloques. ¡O puede llamar a otras funciones de suspensión!
Lo que sucede con el flujo es visible en la siguiente imagen:
Flow emitirá valores de uno en uno. Luego, aplica cada operador a cada uno de los valores, una vez más, uno a la vez. Y finalmente, cuando empieces a consumir valores, los recibirás en el mismo orden.
Cree y ejecute haciendo clic en el botón de reproducción junto a la función principal.
¡Notarás que no pasa nada! Esto se debe a que los operadores intermedios son fríos. Cuando invoca una operación intermedia en un flujo, la operación no se ejecuta inmediatamente. En cambio, devuelve el Flujo transformado, que todavía está frío. Las operaciones se ejecutan solo cuando invoca a un operador de terminal en la secuencia final.
Operadores de terminales
Debido a que los flujos son fríos, no producirán valores hasta que se llame a un operador de terminal. Los operadores de terminales están suspendiendo funciones que inician -- del flujo. Cuando invoca un operador de terminal, invoca a todos los operadores intermedios junto con él:
Un ejemplo de lo que sucedería con los valores originales, si escuchara un flujo:
A medida que comienza a recopilar valores, obtiene uno a la vez y no bloquea mientras espera nuevos valores.
Ahora vuelve a la principal.kt archivo y agregue el collect()
operador de terminal:
fun main () = runBlocking {namesFlow .map {name -> name.length} .filter {length -> length <5} .collect {println (it)} println ()}
Como collect()
es una función de suspensión, solo se puede llamar desde una corrutina u otra función de suspensión. Es por eso que envuelve el código con runBlocking()
.
Cree y ejecute el código haciendo clic en el botón de reproducción. Obtendrá el siguiente resultado:
4 3
collect()
es el operador de terminal más básico. Recopila valores de un flujo y ejecuta una acción con cada elemento. En este caso, está imprimiendo un elemento en la consola. Hay otros operadores de terminales disponibles; aprenderá sobre ellos más adelante en este tutorial.
Puede consultar el código final en el Patio de recreo-Final proyecto.
Ahora que conoce los conceptos básicos de Flow, pasemos a nuestra aplicación meteorológica, ¡donde verá a Kotlin Flow haciendo un trabajo real! :]
Flow en Android
¡Ahora aplicará todo lo que ha aprendido hasta ahora en una aplicación de Android! los sunzoide es una aplicación meteorológica simple que muestra un pronóstico para una ciudad específica. Obtiene los datos meteorológicos de la red y los almacena en una base de datos para admitir el modo fuera de línea.
Abra la Arrancador solar proyecto en Android Studio. Cree y ejecute la aplicación y verá una pantalla vacía:
Hay un icono de búsqueda en la esquina superior izquierda. Puede tocarlo para ingresar una ubicación específica. Si lo hace ahora, no pasará nada. Pero espera, ¡vas a implementar esta funcionalidad a continuación!
Hay una buena cantidad de código en el proyecto de inicio:
Se centrará en el uso de Kotlin Flow en la aplicación. Pero si lo desea, puede explorar el código y familiarizarse con la aplicación.
El proyecto inicial sigue la guía recomendada de Google para la arquitectura de aplicaciones. Puede encontrar la guía en el sitio para desarrolladores de Android documentación:
En la parte superior del esquema, hay una capa de interfaz de usuario que habla con el componente de arquitectura ViewModel. ViewModel se comunica con un repositorio de datos. El repositorio obtiene los datos de la red usando reequipamiento. Almacena los datos en un local Conferencia base de datos. Finalmente, expone los datos de la base de datos al ViewModel.
Room and Retrofit, en sus últimas versiones, son compatibles con Kotlin Coroutines. El proyecto de inicio está configurado para usarlos con corrutinas.
Utilizará Kotlin Flow para pasar los datos de la base de datos al ViewModel. El ViewModel luego recopilará los datos. También utilizará corrutinas y Flow para implementar la función de búsqueda.
Obtener datos
Comenzará implementando la lógica para obtener los datos de pronóstico. Abierto InicioActividad.kt. En onCreate()
, agrega una llamada a fetchLocationDetails()
, justo debajo initUi()
:
homeViewModel.fetchLocationDetails (851128)
fetchLocationDetails()
acepta un cityId
como argumento. Por ahora, pasará la ID codificada. Luego agregará una función de búsqueda que le permitirá buscar una ubicación específica.
Cree y ejecute el proyecto. Seguirá sin ver nada en la pantalla:
¡Pero esta vez la aplicación ha obtenido los datos de pronóstico y los ha guardado en la base de datos de Room! :]
Espacio y flujo
En la Sala 2.1, la biblioteca agregó soporte de corrutinas para operaciones únicas. Room 2.2 agregó compatibilidad con Flow para consultas observables. Esto le permite recibir una notificación cada vez que agregue o elimine entradas en la base de datos.
En la implementación actual, solo el usuario puede activar la obtención de datos. Pero puede implementar fácilmente una lógica que programe y actualice la base de datos cada tres horas, por ejemplo. Al hacer esto, se asegura de que su interfaz de usuario esté actualizada con los datos más recientes. Utilizará Kotlin Flow para recibir notificaciones de cada cambio en la tabla.
Conectarse a la base de datos
Abierto PronósticoDao.kt y agrega una llamada a getForecasts()
. Este método devuelve Flow<List<DbForecast>>
:
@Query ("SELECT * FROM Forecast_table") fun getForecasts (): Flujo >
getForecasts()
devuelve datos de pronóstico para una ciudad específica de forecasts_table
. Siempre que los datos de esta tabla cambian, la consulta se ejecuta de nuevo y Flow
emite datos nuevos.
A continuación, abrir WeatherRepository.kt y agregue una función llamada getForecasts
:
fun getForecasts (): Flujo >
A continuación, agregue la implementación a WeatherRepositoryImpl.kt:
anular diversión getForecasts () = ForecastDao .getForecasts () .map {dbMapper.mapDbForecastsToDomain (it)}
Este método utiliza el forecastDao
para obtener datos de la base de datos. La base de datos devuelve el modelo de base de datos. Es una buena práctica que cada capa de la aplicación funcione con su propio modelo. Utilizando map()
, convierte el modelo de base de datos al Forecast
modelo de dominio.
Abierto InicioViewModel.kt y añade forecasts
, al igual que:
// 1 val pronósticos: LiveData > = weatherRepository // 2 .getForecasts () // 3 .map {homeViewStateMapper.mapForecastsToViewState (it)} // 4 .asLiveData ()
Aquí están sucediendo algunas cosas:
- Primero, declaras
forecasts
de lasLiveData<List<ForecastViewState>>
tipo. losActivity
observará cambios enforecasts
.forecasts
podría haber sido delFlow<List<ForecastViewState>>
tipo, peroLiveData
se prefiere al implementar la comunicación entre View y ViewModel. Esto es porqueLiveData
tiene manejo interno del ciclo de vida! - Siguiente, referencia
weatherRepository
para obtener el flujo de datos de pronóstico. - Luego llame
map()
.map()
convierte los modelos de dominio a laForecastViewState
modelo, que está listo para renderizar. - Finalmente, convierta un
Flow
aLiveData
, utilizandoasLiveData()
. Esta función es de la biblioteca AndroidX KTX paraLifecycle
yLiveData
.
Preservación del contexto y contrapresión
La recopilación de un flujo siempre ocurre en el contexto de la corrutina principal. Esta propiedad de Flow se llama preservación del contexto. Pero aún puede cambiar el contexto al emitir elementos. Para cambiar el contexto de las emisiones, puede utilizar flowOn()
.
Podría tener un escenario en el que el flujo produzca eventos más rápido de lo que el recopilador puede consumirlos. En corrientes reactivas, esto se llama contrapresión. Kotlin Flow admite la contrapresión desde el primer momento, ya que se basa en corrutinas. Cuando el consumidor está en un estado de suspensión o está ocupado haciendo algún trabajo, el productor lo reconocerá. No producirá ningún artículo durante este tiempo.
Observando valores
Finalmente, abre InicioActividad.kt y observar forecasts
en initObservers()
:
homeViewModel.forecasts.observe (esto, Observer {ForecastAdapter.setData (it)})
Siempre que los pronósticos cambien en la base de datos, recibirá nuevos datos en el Observer y los mostrará en la interfaz de usuario.
Cree y ejecute la aplicación. ¡Ahora la pantalla de inicio muestra datos de pronóstico! :]
¡Felicidades! Ha implementado la comunicación entre varias capas de su aplicación usando Flow
y LiveData
!
Cancelación
In InicioViewModel.kt, estás observando el forecasts
. Has notado que nunca dejas de observar. Entonces, ¿cuánto tiempo se observa esto?
En este caso, la colección Flow comienza cuando LiveData
se activa. Entonces sí LiveData
se vuelve inactivo antes de que se complete el flujo, la recolección de flujo se cancela.
La cancelación ocurre después de un retraso cronometrado a menos que LiveData
se activa de nuevo antes de ese tiempo de espera. El retraso predeterminado que activa la cancelación es de 5000 milisegundos. Puede personalizar el valor del tiempo de espera si es necesario. El tiempo de espera existe para manejar casos como cambios en la configuración de Android.
If LiveData
vuelve a activarse después de la cancelación, la colección de Flow se reinicia.
Excepciones
Los flujos de flujo pueden completarse con una excepción si un emisor o código dentro de los operadores arroja una excepción. catch()
los bloques manejan excepciones dentro de los flujos. Puedes hacerlo imperativamente or declarativamente. La try-catch
bloque en el lado del coleccionista es un ejemplo de un INDISPENSABLE enfoque.
Es imperativo porque capturan cualquier excepción que ocurra en el emisor o en cualquiera de los operadores.
Puedes usar catch()
para manejar errores declarativamente en lugar. Declarativo aquí significa que tú declarar la función para manejar errores. Y lo declaras dentro del propio flujo, y no un try-catch
bloquear.
Abierto InicioViewModel.kt y navega a forecasts
. Añadir catch()
justo antes de map()
. Para simular errores en la transmisión, lanza una excepción de map()
:
pronósticos de val: LiveData > = weatherRepository .getForecasts () .catch {// Error de registro} .map {homeViewStateMapper.mapForecastsToViewState (it) throw Exception ()} .asLiveData ()
Cree y ejecute la aplicación. ¡Notarás que la aplicación falla! catch()
solo detecta excepciones aguas arriba. Es decir, detecta excepciones de todos los operadores por encima de la captura. catch()
no detecta ninguna excepción que ocurra después del operador.
Ahora muévete catch()
a continuación map()
:
pronósticos de val: LiveData > = weatherRepository .getForecasts () .map {homeViewStateMapper.mapForecastsToViewState (it) throw Exception ()} .catch {// Error de registro} .asLiveData ()
Compile y ejecute la aplicación nuevamente. Ahora verá una pantalla vacía:
Esto es un ejemplo de transparencia de excepción, donde puede separar el manejo de excepciones que ocurren en el flujo de la colección de valores. También está siendo transparente sobre las excepciones, ya que no oculta ningún error, ¡los maneja explícitamente en un operador!
Antes de continuar, elimine la línea que arroja una excepción de map()
.
Buscando ubicaciones
Hasta ahora, su aplicación mostraba un pronóstico para una ubicación codificada. ¡Ahora implementará la función de búsqueda! Esto permitirá a los usuarios buscar una ubicación específica usando corrutinas y Flow. A medida que el usuario escribe en el cuadro de búsqueda, la aplicación realizará una búsqueda por cada letra escrita y actualizará el resultado de la búsqueda.
In InicioActividad.kt, ya tiene un oyente adjunto a la vista de búsqueda. Cuando el usuario cambia el texto de la consulta, la aplicación envía el nuevo valor a queryChannel
in InicioViewModel.kt. InicioViewModel.kt utiliza una BroadcastChannel
como un puente para pasar el texto de la vista al ViewModel. offer()
pasa el texto y agrega sincrónicamente el elemento especificado al canal.
Consultar ubicaciones
Ahora agregue la lógica para consumir los eventos del canal como un Flow
:
private val _locations = queryChannel // 1 .asFlow () // 2 .debounce (SEARCH_DELAY_MILLIS) // 3 .mapLatest {if (it.length> = MIN_QUERY_LENGTH) {getLocations (it)} else {emptyList ()}} // 4 .catch {// Error de registro}
Esto es lo que sucede en este bloque de código:
- Primero, la llamada a
asFlow
convierte elChannel
post-extracciónFlow
. - Siguiente,
debounce()
espera a que los valores dejen de llegar durante un período de tiempo determinado. Esto se usa para evitar el procesamiento de cada letra escrita por los usuarios. Los usuarios suelen escribir varias letras seguidas. No es necesario realizar una solicitud de red hasta que el usuario deje de escribir. ¡Esto asegura que está realizando la llamada a la API solo después de que hayan pasado 500 milisegundos sin escribir! - Entonces,
mapLatest()
realiza la llamada a la API y devuelve resultados de ubicación. Si el flujo original emite un nuevo valor mientras la llamada API anterior aún está en curso,mapLatest()
asegura que se cancele el cálculo del bloque anterior.mapLatest()
realiza la llamada a la API solo si la consulta de búsqueda contiene al menos dos caracteres. - Finalmente,
catch()
maneja errores.
Añada locations
a InicioViewModel.kt. Esto le permite observar desde la actividad:
val ubicaciones = _locations.asLiveData ()
Aquí estás usando asLiveData()
para recopilar valores del flujo de origen y agregar transformarlos a un LiveData
ejemplo.
Abierto InicioActividad.kt y eliminar la llamada de onCreate()
a homeViewModel.fetchLocationDetails()
. En lugar de observar locations
en initObservers()
:
diversión privada initObservers () {homeViewModel.locations.observe (this, Observer {locationAdapter.setData (it)}) ...}
Una vez más, cree y ejecute la aplicación. Ahora ingrese una consulta de búsqueda. Verá las opciones generadas a partir de su consulta:
Continúe y toque cualquiera de las opciones. La pantalla de inicio mostrará datos de pronóstico para una ubicación recién seleccionada.
Por qué Kotlin Flow
Ya existen otras implementaciones de la especificación de flujo reactivo, como RxJava. Entonces, ¿por qué usar Kotlin Flow? Una razón es que no puede usar bibliotecas específicas de JVM como RxJava en proyectos multiplataforma de Kotlin. Pero Flow es parte del lenguaje Kotlin, por lo que es ideal para usar en proyectos multiplataforma de Kotlin.
Además, Kotlin Flow tiene menos operadores, pero son mucho más simples. ¡Un solo operador puede manejar lógica síncrona y asincrónica ya que el bloque de código que aceptan los operadores puede suspenderse!
Y Kotlin Flow es interoperable con otras corrientes reactivas y corrutinas. Dado que está construido sobre corrutinas, proporciona todas las ventajas de la concurrencia estructurada y la cancelación. En combinación con funciones de suspensión, produce una API simple, legible y comprensible. También admite contrapresión desde el primer momento.
¿A dónde ir desde aquí?
Puedes descargar el proyecto final usando el Descargar materiales botón en la parte superior o inferior de este tutorial.
Ha creado una aplicación que utiliza Kotlin Flow para la comunicación entre capas de aplicaciones. En el proceso, aprendió qué tiene de especial Kotlin Flow y en qué se diferencia de las soluciones existentes. También usó constructores de flujo para crear un flujo. Se familiarizó con los operadores básicos para transformar un flujo de datos. ¡Y finalmente, aplicó operadores de terminal para consumir los valores!
Para obtener un conocimiento más profundo sobre Kotlin Flow, consulte nuestro Kotlin Flow: Introducción curso de video. Aprenderá mucho más sobre los creadores, operadores y cancelaciones de Flow. ¡También aprenderá a trabajar con flujos, cambiar su contexto, agregar búferes, combinar múltiples flujos y manejar excepciones!
¡Esperamos que hayas disfrutado de este tutorial! Si tiene alguna pregunta o comentario para compartir, únase a la discusión del foro a continuación. :]
Fuente: https://www.raywenderlich.com/9799571-kotlin-flow-for-android-getting-started