Generalidades

Hacer consciente el ciclo de vida de Cold Streams | Autor: Hicham Boushaba | Noviembre de 2021

Hicham Busaba
Foto de elnaz asadi en Unsplash

Con la introducción de SharedFlow y StateFlow, muchos desarrolladores están migrando desde LiveDataelectrónico Capa de interfaz de usuario para aprovechar la API de Flow e implementar una API más consistente en todas las capas, pero desafortunadamente, como explicó Christophe Beyls en su publicación, cuando el ciclo de vida de la vista entra en la ecuación, la migración es complicada. Versión 2.4 lifecycle:lifecycle-runtime-ktx Se han introducido API para ayudar en este sentido: repeatOnLifecycle con flowWithLifecycle (Para obtener más información, consulte el artículo: Una forma más segura de recopilar transmisiones desde la interfaz de usuario de Android), en este artículo, intentaremos usarlas, discutiremos un pequeño problema que introducen en algunos casos, vemos Ver si podemos idear una solución más flexible.

Para explicar el problema, imaginemos que tenemos una aplicación de muestra que escucha las actualizaciones de ubicación cuando está activa, y cada vez que hay una nueva ubicación disponible, realiza llamadas a la API para recuperar algunas ubicaciones cercanas.Por lo tanto, para monitorear las actualizaciones de ubicación, escribiremos una clase LocationObserver que proporcione un flujo frío que las devuelva.

Entonces usaremos esta clase en nuestro ViewModel

Por simplicidad, usamos AndroidViewModel acceso Context Directamente, no nos ocuparemos de diferentes casos extremos con respecto a los permisos y la configuración de ubicación.

Ahora, lo que tenemos que hacer en Fragmento es escuchar el derecho viewState Actualice y actualice la interfaz de usuario:

dónde FragmentMainBinding#render Es una extensión que puede actualizar la interfaz de usuario.

Ahora, si intentamos ejecutar la aplicación, cuando la ponemos en segundo plano, veremos que LocationObserver todavía está escuchando actualizaciones de ubicación y luego obtenemos ubicaciones cercanas, incluso si la interfaz de usuario las ignora.

Nuestro primer intento de resolver este problema fue utilizar la nueva API flowWithLifecycle

Si ejecutamos la aplicación ahora, notaremos que imprime la siguiente línea en Logcat cada vez que entra en segundo plano.

D/LocationObserver: stop observing location updates

Entonces la nueva API resuelve este problema, pero hay un problema. Siempre que la aplicación entre en segundo plano y regresemos, perderemos los datos que teníamos antes. Incluso si la ubicación no cambia, volveremos a hacer clic en la API. Esto sucede porque flowWithLifecycle Upstream se cancelará cada vez que se utilice lifecycle Pase a continuación State (Este es Started Para nosotros) y reinícielo de nuevo cuando se restaure el estado.

La solución oficial que se sigue utilizando flowWithLifecycle Como se explica en el artículo de José Alcérreca, utiliza stateIn Pero hay un especial timeout Establezca en 5 segundos para considerar los cambios de configuración, por lo que debemos agregar la siguiente declaración al flujo de nuestro viewState

Esto funciona bien, excepto que detener / reiniciar Flow cada vez que la aplicación ingresa en segundo plano creará otro problema, por ejemplo, no necesitamos obtener la ubicación cercana a menos que la ubicación cambie la distancia mínima, así que cambiemos el código a la siguiente

Si ejecutamos la aplicación ahora, la ponemos en segundo plano durante más de 5 segundos y luego la volvemos a abrir, notaremos que incluso si la ubicación no cambia en absoluto, volveremos a adquirir ubicaciones cercanas, y al mismo tiempo, en La mayoría de los casos, esto no es un gran problema, y ​​puede ser costoso en algunos casos: red lenta, API lenta o computación pesada …

Si podemos hacer nuestro locationUpdates ¿Transmitir conciencia del ciclo de vida, detenerlo sin ninguna interacción explícita de Fragment?De esta manera, podremos dejar de escuchar actualizaciones de ubicación sin tener que reiniciar todo el Flow. Si la ubicación no ha cambiado, entonces vuelve a ejecutar todos los operadores intermedios, e incluso podemos recopilar nuestro viewState Stream se usa con regularidad launchWhenStartedPorque nos aseguraremos de que no se ejecute porque no hemos emitido ninguna ubicación.

Si podemos tener un flujo de calor interno dentro del ViewModel, observemos el estado de la Vista:

Entonces podremos tener una extensión que detiene y reinicia nuestro flujo ascendente según el ciclo de vida:

De hecho, podemos usar LifecycleEventObserver Interfaz del programa de aplicación

Podemos usarlo para conectarnos a los eventos del ciclo de vida de Fragment:

Con esto, ahora podemos actualizar nuestro locationUpdates Fluir debajo

Podemos observar nuestro viewState Fluya regularmente en Fragmento, no hay necesidad de preocuparse por mantener el GPS encendido cuando la aplicación ingresa en segundo plano

nombre de la extensión whenAtLeast Es flexible porque se puede aplicar a cualquier Flow en la cadena, no solo durante el período de recolección, sino que, como hemos visto, aplicándolo al flujo de activación upstream (actualización de ubicación en nuestro caso), resultando en menos cálculos:

  • A menos que sea necesario, los operadores intermedios, incluida la extracción de ubicaciones cercanas, no se ejecutarán.
  • No volveremos a enviar los resultados a la interfaz de usuario cuando regresemos del fondo, porque no cancelaremos la recopilación.

Si desea ver el código completo en Github: https://github.com/hichamboushaba/FlowLifecycle, y el código completo incluye un ejemplo de cómo podemos usar estos cambios para probar nuestro ViewModel.

Como puede ver, usar Kotlin Flows en la capa de la interfaz de usuario todavía no es siempre tan simple, pero aún lo prefiero a LiveData, puede acceder a todas sus API y usar API consistentes en todas las capas. Para los problemas que estamos discutiendo aquí, personalmente, solo puse la lógica explicada en BaseFragment / BaseViewModel, y luego puedo usarla en todas las pantallas sin ningún texto repetitivo, y ha estado en mi aplicación personal desde 2018 El programa funciona bien. Esperemos que esta solicitud de función se implemente para proporcionar una forma de cooperar para suspender la recopilación sin cancelarla, lo que resolverá por completo el problema.

¿Qué opinas de la solución explicada en este artículo? ¿Perdí una solución más simple a este problema? Déjame saber los comentarios.

LEER  Obtenga más información sobre las corrutinas de Kotlin. | Por KUNAL PASRICHA | Diciembre de 2021

Publicaciones relacionadas

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba