Logotipo de Zephyrnet

Kotlin Flow para Android: Primeros pasos [GRATIS]

Fecha:

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.
Note: Este tutorial asume que tienes un conocimiento sólido del desarrollo de Android. Si es completamente nuevo en el tema, consulte nuestro Inicio del desarrollo de Android con la serie Kotlin primero.

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:

Diagrama de lista

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 Iterators 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 Sequences para flujos síncronos. Pero necesita una solución diferente para transmisiones asincrónicas.

Para transmisiones asincrónicas, puede usar Channels 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:

Diagrama de secuencia

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:

Diagrama de filtro de flujo

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:

Diagrama de funcionamiento del terminal

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:

Pantalla inicial Sunzoid

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:

Estructura del proyecto Sunzoid

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:

Arquitectura recomendada por Google

Derechos de autor 2020 Google LLC

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:

Pantalla vacía Sunzoid

¡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:

  1. Primero, declaras forecasts de las LiveData<List<ForecastViewState>> tipo. los Activity observará cambios en forecasts. forecasts podría haber sido del Flow<List<ForecastViewState>> tipo, pero LiveData se prefiere al implementar la comunicación entre View y ViewModel. Esto es porque LiveData tiene manejo interno del ciclo de vida!
  2. Siguiente, referencia weatherRepository para obtener el flujo de datos de pronóstico.
  3. Luego llame map(). map() convierte los modelos de dominio a la ForecastViewState modelo, que está listo para renderizar.
  4. Finalmente, convierta un Flow a LiveData, utilizando asLiveData(). Esta función es de la biblioteca AndroidX KTX para Lifecycle y LiveData.

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! :]

Sunzoid con 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:

Excepción arrojada por Sunzoid

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:

  1. Primero, la llamada a asFlow convierte el Channel post-extracción Flow.
  2. 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!
  3. 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.
  4. 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:

Sunzoid con consulta de ubicación

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

punto_img

Información más reciente

punto_img