Explicación detallada y uso de Android LiveData

1. ¿Qué es LiveData?

LiveDataes una clase de almacenamiento de datos observables.

A diferencia de las clases observables normales, LiveDatatiene en cuenta el ciclo de vida, lo que significa que sigue el ciclo de vida de otros componentes de la aplicación, como Activity, Fragmento . ServiceEste reconocimiento garantiza que LiveDatasolo se actualicen los observadores de los componentes de la aplicación que se encuentran en un estado de ciclo de vida activo.

Un observador (representado por una clase) se considera activo si Observersu tiempo de vida se encuentra en el estado STARTEDo . Solo los observadores activos serán notificados de las actualizaciones. Los observadores inactivos registrados para observar el objeto no serán notificados de los cambios.RESUMEDLiveDataLiveDataLiveData

Puede registrar LifecycleOwnerobservadores emparejados con objetos que implementan la interfaz. Con esta relación establecida, el observador puede eliminarse cuando Lifecyclecambia el estado del objeto correspondiente . DESTROYEDEsto es especialmente útil para Activityy Fragment, ya que pueden observar LiveDataobjetos de forma segura sin preocuparse por las fugas (el sistema los cancela inmediatamente cuando se destruye Activitysu Fragmentvida útil).

2. Ventajas de LiveData

El uso LiveDatatiene las siguientes ventajas:

  • Asegúrese de que la interfaz se ajuste al estado de los datos

    LiveDataSigue el patrón del observador. LiveDataEl objeto ** es notificado cuando los datos subyacentes cambian Observer. Puede incorporar código para Observeractualizar la interfaz en estos objetos. De esta manera, no necesita actualizar su interfaz de usuario cada vez que cambien los datos de su aplicación, porque el observador lo hará por usted.

  • sin fugas de memoria

    Los observadores están vinculados a Lifecyclelos objetos y se limpian después de que se destruyen sus ciclos de vida asociados.

  • No se bloquea cuando la actividad se detiene

    Si el tiempo de vida del observador está inactivo (como en la pila trasera Activity), no es bueno recibir ningún LiveDataevento

  • No más manejo manual de ciclos de vida

    Los componentes de la interfaz de usuario simplemente observan los datos relevantes y no detienen ni reanudan la observación. LiveDataTodas estas operaciones se gestionan automáticamente, ya que está al tanto de los cambios de estado del ciclo de vida relevantes que observa.

  • Los datos siempre están actualizados

    Si un ciclo de vida se vuelve inactivo, recibirá los datos más recientes cuando vuelva a estar activo. Por ejemplo, una actividad que una vez estuvo en segundo plano recibe los datos más recientes tan pronto como vuelve al primer plano.

  • Cambios de configuración apropiados

    ActivitySi o se vuelve a crear debido a un cambio de configuración, como la rotación de un dispositivo Fragment, recibe inmediatamente los últimos datos disponibles.

  • Compartir recurso

    Puede usar el patrón singleton para extender LiveDataobjetos para encapsular servicios del sistema para que puedan compartirse entre aplicaciones. LiveDataEl objeto se conecta al servicio del sistema una vez, y luego cualquier observador que necesite el recurso correspondiente simplemente observa LiveDatael objeto.

3. Usa el objeto LiveData

Siga los pasos a continuación para usar LiveDatael objeto:

  1. Se crea una instancia de LiveDatapara almacenar algún tipo de datos. Esto generalmente ViewModelse hace en las clases.

  2. Crea un objeto onChanged()que define Observerun método que controla LiveDatalo que sucede cuando cambian los datos almacenados por el objeto. Por lo general, los objetos se crean Observeren un controlador de interfaz, como una Actividad o un Fragmento.

  3. Utilice observe()el método para Observeradjuntar el objeto al LiveDataobjeto. observe()El método toma LifecycleOwnerun objeto. Esto hace que Observerel objeto se suscriba al LiveDataobjeto para que se le notifiquen los cambios. Por lo general, adjunta Observerobjetos en un controlador de interfaz, como una actividad o un fragmento.

    Nota : Puede utilizar observeForever(Observer)el método para registrar un observador sin un LifecycleOwnerobjeto asociado. En este caso, se considera que el observador está siempre activo, por lo que siempre se le notifican las modificaciones. Puede removeObserver(Observer)eliminar estos observadores llamando al método.

Cuando actualiza LiveDatael valor almacenado en el objeto, activa todos los observadores registrados (siempre que el adjunto LifecycleOwneresté activo).

LiveDataPermite que los observadores del controlador de IU se suscriban a las actualizaciones. Cuando LiveDatalos datos en el almacén de objetos cambian, la interfaz se actualiza automáticamente para responder.

  • crear LiveDataobjeto

    LiveDataes un contenedor que se puede usar para cualquier dato, incluidos Collectionslos objetos que implementan, como List. LiveDataLos objetos normalmente se almacenan en ViewModelobjetos y se accede a ellos a través de métodos getter, como se muestra en el siguiente ejemplo:

    public class NameViewModel extends ViewModel {
          
          
    
    // Create a LiveData with a String
    private MutableLiveData<String> currentName;
    
        public MutableLiveData<String> getCurrentName() {
          
          
            if (currentName == null) {
          
          
                currentName = new MutableLiveData<String>();
            }
            return currentName;
        }
    
    // Rest of the ViewModel...
    }
    

    Inicialmente, LiveDatalos datos en el objeto no están configurados.

Nota : asegúrese de que LiveDatael objeto utilizado para actualizar la interfaz ViewModelesté almacenado en el objeto, no en la Actividad o el Fragmento, por las siguientes razones: Evite Actividades y Fragmentos demasiado grandes. Ahora, estos controladores de interfaz de usuario son responsables de mostrar datos, pero no de almacenar el estado de los datos. Separe LiveDatala instancia de una instancia específica de Actividad o Fragmento y permita que LiveDatael objeto sobreviva a los cambios de configuración

  • LiveDataobjeto de observación

    En la mayoría de los casos, onCreate()el método de aplicación de un componente es LiveDatael lugar correcto para comenzar a observar un objeto por las siguientes razones:

    • Asegúrese de que el sistema no realice llamadas redundantes desde onResume()los métodos Actividad o Fragmento.
    • Asegúrese de que la Actividad o el Fragmento tenga datos que se puedan mostrar inmediatamente después de que se active. Una vez que un componente de la aplicación está en STARTEDestado, recibe el valor más reciente del objeto que está observando LiveData. LiveDataEsto solo sucede cuando se establece un objeto para observar .

    Normalmente, LiveData solo envía actualizaciones cuando los datos cambian y solo a los observadores activos. Una excepción a este comportamiento es que los observadores también reciben actualizaciones cuando pasan de inactivos a activos. Además, si el observador cambia de inactivo a activo por segunda vez, solo recibirá actualizaciones si el valor ha cambiado desde la última vez que estuvo activo.

    El siguiente código de ejemplo ilustra cómo comenzar a observar LiveDataobjetos:

    public class NameActivity extends AppCompatActivity {
          
          
    
        private NameViewModel model;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
          
          
            super.onCreate(savedInstanceState);
    
            // Other code to setup the activity...
    
            // Get the ViewModel.
            model = new ViewModelProvider(this).get(NameViewModel.class);
    
            // Create the observer which updates the UI.
            final Observer<String> nameObserver = new Observer<String>() {
          
          
                @Override
                public void onChanged(@Nullable final String newName) {
          
          
                    // Update the UI, in this case, a TextView.
                    nameTextView.setText(newName);
                }
            };
    
            // Observe the LiveData, passing in this activity as the LifecycleOwner and the observer.
            model.getCurrentName().observe(this, nameObserver);
        }
    }
    

    nameObserverCuando se llama con el parámetro pasado observe(), se llama inmediatamente onChanged(), proporcionando mCurrentNameel último valor almacenado en el archivo . No se llamará si LiveDatael objeto aún no tiene un valor establecido en .mCurrentNameonChanged()

  • actualizar LiveDataobjeto

    LiveData no tiene métodos disponibles públicamente para actualizar los datos almacenados. MutableLiveDataLa clase expondrá métodos, que deben usarse setValue(T)si postValue(T)necesita modificar el valor almacenado en el objeto. LiveDataNormalmente se usaría ViewModelen MutableLiveData, luego ViewModelsolo expone LiveDataobjetos inmutables a los observadores.

    Después de configurar las relaciones de los observadores, puede actualizar LiveDatael valor del objeto (como en el siguiente ejemplo) para que todos los observadores se activen cuando el usuario toque un botón:

    button.setOnClickListener(new OnClickListener() {
          
          
        @Override
        public void onClick(View v) {
          
          
            String anotherName = "John Doe";
            model.getCurrentName().setValue(anotherName);
        }
    });
    

Llamar en este ejemplo setValue(T)hace que el observador John Doellame a su onChanged()método con el valor . Este ejemplo muestra cómo presionar un botón, pero también puede llamar setValue()o postValue()actualizar por una variedad de razones mName, incluso en respuesta a una solicitud de red o cuando se completa la carga de una base de datos. En todos los casos, llama setValue()o postValue()dispara al observador y actualiza la interfaz.

Nota : debe llamar setValue(T)al método para actualizar LiveDatael objeto desde el hilo principal. Si ejecuta código en un subproceso de trabajo, puede usar postValue(T)el método para actualizar LiveDatael objeto en su lugar.

  • Usar LiveDatacon Habitación

    La biblioteca de persistencia de Room admite LiveDataconsultas observables que devuelven objetos. Las consultas observables son parte de los objetos de acceso a la base de datos (DAO).

    Cuando se actualiza la base de datos, Room genera LiveDatatodo el código necesario para actualizar los objetos. El código generado ejecuta la consulta de forma asíncrona en un subproceso en segundo plano cuando es necesario. Este patrón ayuda a mantener los datos que se muestran en la interfaz de usuario sincronizados con los datos almacenados en la base de datos. Puede obtener más información sobre las salas y las DAO en la guía de la biblioteca de persistencia de salas .

4. LiveData en la arquitectura de aplicaciones

LiveDataTiene conciencia del ciclo de vida y sigue el ciclo de vida de entidades como y activity. Puede pasar datos entre estos propietarios de por vida y otros objetos con diferentes vidas, como objetos, fragmentusando La responsabilidad principal de es cargar y administrar datos relacionados con la interfaz, por lo que es muy adecuado como método alternativo para la persistencia de objetos. Puede crear objetos y luego usarlos para exponer el estado en la capa de la interfaz de usuario.LiveDataViewModelViewModelLiveDataViewModelLiveData

activityy fragmentno deben persistir LiveDatainstancias porque su propósito es mostrar datos, no mantener el estado. Además, facilita la escritura de pruebas unitarias al hacer que las actividades y los fragmentos sean persistentes sin datos persistentes.

Es posible que tenga la tentación de usar objetos en sus clases de capa de datos LiveData, pero LiveDatano es adecuado para manejar flujos de datos asíncronos. Si bien puede usar LiveDatatransformaciones MediatorLiveDatapara lograrlo, las desventajas de este enfoque son que existe una funcionalidad muy limitada para combinar flujos de datos y todos los LiveDataobjetos (incluidos los creados por transformaciones) se observan en el subproceso principal. Aquí hay un código de muestra que muestra cómo Repositoryretener en LiveDataun bloquea el hilo principal:

class UserRepository {
    
    

    // DON'T DO THIS! LiveData objects should not live in the repository.
    LiveData<List<User>> getUsers() {
    
    
        ...
    }

    LiveData<List<User>> getNewPremiumUsers() {
    
    
    return Transformations.map(getUsers(),
        // This is an expensive call being made on the main thread and may cause
        // noticeable jank in the UI!
        users -> users.stream()
            .filter(User::isPremium)
            .filter(user ->
                user.getTimeCreated() > dao.getLastSyncedTime())
            .collect(Collectors.toList()));
    }
}

Si necesita usar flujo de datos en otras capas de su aplicación, considere usar Kotlin Flow y luego convierta Kotlin Flow para usar asLiveData()en . Obtenga más información sobre el uso de Kotlin con Kotlin en este laboratorio de programación . Para las bases de código construidas en Java, considere usar ejecutores con devoluciones de llamada o .ViewModelLiveDataFlowLiveDataRxJava

5. Ampliar LiveData

Un observador se considera activo si su tiempo de vida se encuentra en el estado STARTEDo . El siguiente código de ejemplo ilustra cómo extender una clase:RESUMEDLiveDataLiveData

public class StockLiveData extends LiveData<BigDecimal> {
    
    
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
    
    
        @Override
        public void onPriceChanged(BigDecimal price) {
    
    
            setValue(price);
        }
    };

    public StockLiveData(String symbol) {
    
    
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
    
    
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
    
    
        stockManager.removeUpdates(listener);
    }
}

La implementación del detector de precios en este ejemplo incluye los siguientes métodos importantes:

  • LiveDataEl método se llama cuando el objeto tiene observadores activos onActive(). Eso significa que debe comenzar a ver las actualizaciones del precio de las acciones desde este método.
  • LiveDataEl método se llama cuando el objeto no tiene ningún observador activo onInactive(). Dado que no hay observadores escuchando, no hay razón StockManagerpara mantener una conexión con el servicio.
  • setValue(T)El método actualizará LiveDatael valor de la instancia y notificará a los observadores activos del cambio.

Puedes usar StockLiveDatala clase de la siguiente manera:

public class MyFragment extends Fragment {
    
    
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    
    
        super.onViewCreated(view, savedInstanceState);
        LiveData<BigDecimal> myPriceListener = ...;
        myPriceListener.observe(getViewLifecycleOwner(), price -> {
    
    
            // Update the UI.
        });
    }
}

observe()al método se le pasa Fragmentla vista asociada LifecycleOwnercomo primer parámetro. Si lo hace, indica que este observador está vinculado al objeto asociado con el propietario Lifecycle, lo que significa:

  • Si Lifecycleel objeto no está vivo, no se llamará al observador aunque cambie el valor.
  • LifecycleLos observadores se eliminan automáticamente cuando se destruye el objeto.

LiveDataEl hecho de que los objetos sean conscientes del ciclo de vida significa que puede compartir estos objetos entre múltiples Activityy Fragment. ServicePara simplificar el ejemplo, puede LiveDataimplementar la clase como un singleton, así:

public class StockLiveData extends LiveData<BigDecimal> {
    
    
    private static StockLiveData sInstance;
    private StockManager stockManager;

    private SimplePriceListener listener = new SimplePriceListener() {
    
    
        @Override
        public void onPriceChanged(BigDecimal price) {
    
    
            setValue(price);
        }
    };

    @MainThread
    public static StockLiveData get(String symbol) {
    
    
        if (sInstance == null) {
    
    
            sInstance = new StockLiveData(symbol);
        }
        return sInstance;
    }

    private StockLiveData(String symbol) {
    
    
        stockManager = new StockManager(symbol);
    }

    @Override
    protected void onActive() {
    
    
        stockManager.requestPriceUpdates(listener);
    }

    @Override
    protected void onInactive() {
    
    
        stockManager.removeUpdates(listener);
    }
}

y puedes Fragmentusarlo dentro de esta manera:

public class MyFragment extends Fragment {
    
    
    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    
    
        super.onViewCreated(view, savedInstanceState);
        StockLiveData.get(symbol).observe(getViewLifecycleOwner(), price -> {
    
    
            // Update the UI.
        });
    }
}

Instancias múltiples Fragmenty Activityobservables . Solo conéctese a MyPriceListeneruno o más servicios del sistema si están visibles y activos .LiveData

6. Convertir datos en vivo

Es posible que desee LiveDatarealizar cambios en los valores almacenados en el objeto antes de enviarlo a los observadores, o es posible que deba devolver una LiveDatainstancia diferente en función del valor de otra instancia. LifecycleEl paquete proporciona Transformationsla clase, que incluye métodos auxiliares para estas situaciones.

  • Transformations.map()
LiveData<User> userLiveData = ...;
LiveData<String> userName = Transformations.map(userLiveData, user -> {
    
    
    user.name + " " + user.lastName
});
  • Transformations.switchMap()

    Similar a map(), aplica una función al valor almacenado en LiveDatael objeto y desempaqueta y envía el resultado aguas abajo. Una función pasada switchMap()a debe devolver LiveDataun objeto, como se muestra en el siguiente ejemplo:

private LiveData<User> getUser(String id) {
    
    
  ...;
}

LiveData<String> userId = ...;
LiveData<User> user = Transformations.switchMap(userId, id -> getUser(id) );

Puede utilizar el método de transición para transmitir información durante la vida del observador. LiveDataLas transformaciones no se evalúan a menos que un observador esté observando el objeto devuelto . Debido a que las transiciones se calculan con pereza, el comportamiento relacionado con el ciclo de vida se transmite implícitamente sin dependencias ni llamadas explícitas adicionales.

Si cree que ViewModelnecesita Lifecycleun objeto dentro de un objeto, una conversión podría ser una mejor solución. Por ejemplo, suponga que tiene un componente de interfaz que toma una dirección y devuelve el código postal de esa dirección. Puede implementar un simple para este componente ViewModel, como se muestra en el siguiente código de ejemplo:

class MyViewModel extends ViewModel {
    
    
    private final PostalCodeRepository repository;
    public MyViewModel(PostalCodeRepository repository) {
    
    
       this.repository = repository;
    }

    private LiveData<String> getPostalCode(String address) {
    
    
       // DON'T DO THIS
       return repository.getPostCode(address);
    }
}

El componente de la interfaz necesita anular el registro del LiveDataobjeto anterior y getPostalCode()registrarse con la nueva instancia cada vez que se llama. Además, si se vuelve a crear el componente de la interfaz de usuario, activará otra repository.getPostCode()llamada al método en lugar de utilizar el resultado de la llamada anterior.

También puede implementar una búsqueda de código postal como una transformación de una entrada de dirección, como se muestra en el siguiente ejemplo:

class MyViewModel extends ViewModel {
    
    
    private final PostalCodeRepository repository;
    private final MutableLiveData<String> addressInput = new MutableLiveData();
    public final LiveData<String> postalCode =
            Transformations.switchMap(addressInput, (address) -> {
    
    
                return repository.getPostCode(address);
             });

  public MyViewModel(PostalCodeRepository repository) {
    
    
      this.repository = repository
  }

  private void setInput(String address) {
    
    
      addressInput.setValue(address);
  }
}

En este caso, postalCodelos campos se definen como addressInputtransformaciones de . Siempre que su aplicación tenga postalCodeun observador activo asociado con el campo, el valor del campo se addressInputrecalculará y recuperará cada vez que cambie.

Este mecanismo permite que las aplicaciones de nivel inferior creen objetos que se calculan bajo demanda de forma perezosa LiveData. ViewModelLos objetos pueden obtener fácilmente LiveDatareferencias a objetos y luego definir reglas de transformación basadas en ellos.

  • Crear nueva transformación

Hay una docena de transformaciones específicas diferentes que pueden ser útiles en su aplicación, pero no se proporcionan de forma predeterminada. Para implementar sus propias transformaciones, puede usar MediatorLiveDatala clase, que escucha otros LiveDataobjetos y maneja los eventos emitidos por ellos. MediatorLiveDataPropaga su estado al LiveDataobjeto de origen correctamente. Para obtener más información sobre este patrón, consulte Transformationsla documentación de referencia de la clase.

7. Combinar múltiples fuentes de LiveData

MediatorLiveDataEs LiveDatauna subclase que le permite combinar múltiples LiveDatafuentes. LiveDataEl observador del objeto se activa cada vez que cambia cualquiera de los objetos de origen originales MediatorLiveData.

Por ejemplo, si tiene un objeto en su interfaz que se puede actualizar desde una base de datos local o la red LiveData, puede MediatorLiveDataagregar la siguiente fuente al objeto:

  • Objetos asociados con los datos almacenados en la base de datos LiveData.
  • Un objeto asociado con los datos a los que se accede desde la red LiveData.

Su actividad MediatorLiveDatapuede recibir actualizaciones de ambas fuentes simplemente observando el objeto.

Supongo que te gusta

Origin blog.csdn.net/klylove/article/details/122039737
Recomendado
Clasificación