Red de conocimiento informático - Aprendizaje de código fuente - Errores del uso de LiveData para la entrega de eventos

Errores del uso de LiveData para la entrega de eventos

No es necesario mencionar las ventajas de utilizar el patrón de observador para crear un bus de eventos (por supuesto, existen muchas deficiencias). Por ejemplo, EventBus y RxBus, si se usan correctamente, pueden tener un buen efecto de desacoplamiento, lo que hace que toda la estructura del programa sea más clara. tener que pasar varias devoluciones de llamada. Sin embargo, carecen de la capacidad de detectar el ciclo de vida de la capa de Vista (Actividad, Fragmento, etc.) y requieren la eliminación manual de los observadores al final del ciclo de vida, lo que hace que la gestión manual del ciclo de vida sea muy tediosa y propensa a errores.

La biblioteca de ciclo de vida de Google está diseñada para resolver este problema y LiveData es un observador consciente del ciclo de vida, por lo que usarlo para crear un bus de eventos consciente del ciclo de vida sería una buena opción.

A medida que el uso y la comprensión de LiveData se profundizaron gradualmente, especialmente su "conciencia del ciclo de vida", poco a poco me di cuenta de algunos malentendidos sobre el uso de LiveData de esta manera, así que pensé que me gustaría aprovechar esta oportunidad para compartir y Discuta estos mitos con usted. Por lo general, uso LiveData únicamente como entrega de eventos, especialmente para operaciones de lista, como operaciones de IO que involucran adiciones y eliminaciones, en cuyo caso la capa de Vista necesita saber qué datos cambiaron y si la operación fue exitosa, lo cual solo se puede hacer con eventos) .

Como mencioné en mi artículo anterior, también puedes ver el código fuente directamente. postValue simplemente guarda los datos entrantes en mPendingData y luego lanza un Runnable al hilo principal, que llamará a setValue para establecer el valor guardado y volver a llamar al observador. Si publica PostValue varias veces antes de que se ejecute Runnable, entonces en realidad solo está cambiando el valor almacenado en mPendingData en lugar de lanzar otro Runnable, lo que causará problemas con setValue sobrescribiendo el Runnable anterior y provocando que se pierda el evento.

Aquí es donde entra en juego el conocimiento del ciclo de vida de LiveData, ya que no vuelve a llamar a los observadores "inactivos" (es decir, después de onStart, antes de onPause), lo que hace que actualizar la Vista sea inútil y arriesgado; en lugar de eso, espere hasta. el observador está activo antes de recuperar el nuevo valor.

Sin embargo, si paso varios datos (asumiendo que se garantiza que setValue no sobrescribirá todos los datos), entonces los observadores inactivos no sabrán nada al respecto, solo los recibirán cuando se activen. últimos datos. Para la entrega de eventos, este es un evento perdido. Todos los datos pasados ​​en este evento no se recibirán y se perderá el significado de la entrega del evento.

A partir de estos dos puntos, se puede ver que a LiveData (o su observador) no le importa cuántos cambios de datos haya experimentado antes de que se active el observador, solo cambia el último valor cuando se activa el observador. Pasado al observador sin ningún cambio intermedio.

Por supuesto, LiveData no se utiliza para entregar eventos, sino para reflejar el estado actual de la vista. La capa de vista solo necesita presentar datos basados ​​en el valor actual de LiveData. No puedo ver el valor de LiveData, por lo que no tiene sentido actualizarlo.

Mi primer pensamiento fue el bus de eventos porque LiveData usa el patrón de observador y puede comunicar datos entre diferentes fragmentos, pero ahora siento que soy demasiado joven e ingenuo.

Por supuesto, LiveData no está exento de esperanza. Con las potentes bibliotecas de ciclo de vida de Google, podemos crear nuestros propios LiveData sin perder eventos.

Todo lo demás sobre LiveData funciona perfectamente excepto que pierde eventos, por lo que tenemos que resolver cada uno de los problemas anteriores para convertirlo.

Para el problema postValue, dado que eventualmente llamará a setValue y los datos se perderán, debido a que solo lanza Runable una vez, podemos resolver el problema lanzando Runable al hilo principal cada vez

De hecho, creo que la principal responsabilidad de este problema no recae en LiveData, sino en sus observadores. De hecho, creo que la principal "responsabilidad" de este problema no está en LiveData, sino en sus observadores, "Me dices que estás inactivo, entonces, ¿cómo puedo enviarte datos? Si te envío datos, si tienes un problema". , ¿quién es el responsable?

El observador que utilizamos habitualmente es en realidad LifecycleBoundObserver, que se llama public void observe(@NonNull LifecycleOwner propietario, @NonNull Observerlt;? super Tgt; observador), encapsulará uno automáticamente de los observadores para nosotros y presenta los estados "activo" e "inactivo" según el ciclo de vida de LifecycleOwner.

LiveData tiene otro observador por defecto, a saber, AlwaysActiveObserver, que es lo que estamos haciendo. Llamar public void. observeForever(@NonNull Observerlt;? Por supuesto, LiveData no administrará el ciclo de vida de dicho observador por nosotros. Necesitamos llamar manualmente a public void removeObserver(@NonNull final Observerlt super Tgt; observer super Tgt; observador cuando no esté en uso) ) para eliminar observadores no utilizados, de lo contrario podemos tener pérdidas de memoria.

Parece que este AlwaysActiveObserver resolverá nuestro problema, siempre está activo y luego se le devuelven todos los eventos, pero necesitamos administrar el ciclo de vida nosotros mismos. ¿No es esto un paso atrás para darnos cuenta de que el ciclo de vida es muy difícil y ahora tenemos que administrarlo manualmente? AlwaysActiveObserver resuelve el problema que acabamos de describir, así que creemos un nuevo observador para administrar observeForever y eliminarObserver. créelo, primero creemos un observador que funcione; de ​​lo contrario, no podemos perder eventos. No tiene sentido y necesitamos observadores para administrar el ciclo de vida, no solo observeForever y removeObserver, sino que también tengan en cuenta factores como la inactividad. >

Dado que tenemos que administrar el ciclo de vida, debemos usar un LifecycleOwner, Lifecycle y luego observar el ciclo de vida de LifecycleOwner usted mismo.

Lifecycle solo proporciona esta interfaz al mundo exterior. No incluye ninguna devolución de llamada, por lo que debemos usar la anotación OnLifecycleEvent para marcar la función correspondiente. Lifecycle obtendrá la función marcada a través de la reflexión y generará el adaptador correspondiente. Si está interesado, puede consultar la función Lifecycling.getCallback.

Por ejemplo, podemos usarlo así

Una vez que tengamos el ciclo de vida, podemos usar observeForever al principio y eliminarObserver en Lifecycle.Event.ON_DESTROY. evento.ON_DESTROY.

A continuación, debemos considerar los estados activo e inactivo. Como usamos observeForever, cada evento tendrá una devolución de llamada y, si el ciclo de vida está activo, podemos enviar el evento directamente. Si Lifecycle está activo, podemos enviar eventos directamente, pero si Lifecycle está inactivo, no podemos enviar eventos directamente y no podemos perder eventos, por lo que primero debemos almacenar los eventos y luego almacenar los eventos cuando Lifecycle esté activo. Enviarlo . Dibujé un diagrama de flujo simple.

3.1 también mencionó que debemos manejar postValue nosotros mismos. En segundo lugar, para asegurarnos de usar nuestro propio observador definido, debemos anular public void observe (@NonNull LifecycleOwner propietario, @NonNull Observerlt;? super Tgt. ; observador).

Hay algunas otras piezas de este kit que suelo utilizar y que compartiré brevemente contigo aquí: