Bienvenido, soy Miguel y aquí les traigo un artículo.
Índice
Introducción
LiveData
es de la JetPack
familia. Se usa principalmente para entregar datos del modelo de vista a fragmentos y actividades en las últimas arquitecturas, como MVVM
y clean
.
LiveData
es una clase de contenedor de datos observable. A diferencia de otros titulares de los datos, LiveData
es un ciclo de vida tanto de los respectivos componentes como Activities
, Fragments
, services
, y mucho más.
Como es un ciclo de vida consciente, LiveData
se asegura de que solo publique los datos para aquellos que lo están observando cuando están activos, es decir, cuando están en primer plano.
Problema
LiveData
publica los datos en el componente de destino si está en primer plano. Si no es así, podría contener los datos y entregarlos cuando ese componente específico vuelva al primer plano, como en estado onResume
.
Ahora que sabemos cómo funciona, digamos que tenemos un livedata
con múltiples observadores y tres fragmentos (F1
, F2
y F3
) que están en la pila. Los tres fragmentos comparten un ViewModel
y observar un liveData
de tipo T
para mostrar un mensaje.
T
a liveData
, debido a que el fragmento F3
está en primer plano, el mensaje se muestra primero en F3
. Eso es bueno, pero ¿qué sucede cuando hacemos clic para volver?
Se reanuda el fragmento F2
, ya que F2
es uno de sus suscriptores. LiveData
entrega los datos nuevamente, por lo que el mensaje se muestra dos veces y el mismo se repite con el fragmento F1
.
Así es como livedata
funciona pero, en tiempo real, puede haber casos en los que una vez que se observan los datos, no deberían volver a observarse. La siguiente sección contiene la solución.
Solución
Primero, necesitamos crear una clase con el nombre Event
para envolver los datos que livedata
está exponiendo. Eche un vistazo a cómo crear una clase Event
:
/** * Used as a wrapper for data that is exposed via a LiveData that represents an event. */ open class Event<out T>(private val content: T) { var hasBeenHandled = false private set // Allow external read but not write /** * Returns the content and prevents its use again. */ fun getContentIfNotHandled(): T? { return if (hasBeenHandled) { null } else { hasBeenHandled = true content } } /** * Returns the content, even if it's already been handled. */ fun peekContent(): T = content }
En esta clase, mantenemos una bandera hasBeenHandled
para verificar si los datos se observan al menos una vez.
Ahora necesitamos crear otra clase con un nombre EventObserver
que se extienda Observer
. Solo para simplificar el proceso de uso, eche un vistazo:
/** * An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has * already been handled. * * [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled. */ class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> { override fun onChanged(event: Event<T>?) { event?.getContentIfNotHandled()?.let { value -> onEventUnhandledContent(value) } } }
Cuando se publican nuevos datos, la función onChanged
se activa y el indicador hasBeenHandled
se establece en falso.
Tan pronto como el primer suscriptor observe los datos, la bandera hasBeenHandled
será verdadera, de modo que el resto de suscriptores no recibirán los datos y el ciclo se repite cada vez que se publican nuevos datos.
Mientras observamos livedata
, necesitamos usar EventObserver
en lugar de regular Observer
para simplificar el manejo. Echar un vistazo:
viewModel.observeingdata.observe(this, EventObserver { id -> })
Esta es la solución que encontré en el código fuente de la aplicación AndroidDev Summit 2020.
Espero que te haya sido de utilidad. Gracias por leer.
Añadir comentario