Directorio de artículos
1. ¿Qué es LiveData?
LiveData
es una clase de almacenamiento de datos observables.
A diferencia de las clases observables normales, LiveData
tiene en cuenta el ciclo de vida, lo que significa que sigue el ciclo de vida de otros componentes de la aplicación, como Activity
, Fragment
o . Service
Este reconocimiento garantiza que LiveData
solo 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 Observer
su tiempo de vida se encuentra en el estado STARTED
o . 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.RESUMED
LiveData
LiveData
LiveData
Puede registrar LifecycleOwner
observadores emparejados con objetos que implementan la interfaz. Con esta relación establecida, el observador puede eliminarse cuando Lifecycle
cambia el estado del objeto correspondiente . DESTROYED
Esto es especialmente útil para Activity
y Fragment
, ya que pueden observar LiveData
objetos de forma segura sin preocuparse por las fugas (el sistema los cancela inmediatamente cuando se destruye Activity
su Fragment
vida útil).
2. Ventajas de LiveData
El uso LiveData
tiene las siguientes ventajas:
-
Asegúrese de que la interfaz se ajuste al estado de los datos
LiveData
Sigue el patrón del observador.LiveData
El objeto ** es notificado cuando los datos subyacentes cambianObserver
. Puede incorporar código paraObserver
actualizar 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
Lifecycle
los 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únLiveData
evento -
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.
LiveData
Todas 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
Activity
Si o se vuelve a crear debido a un cambio de configuración, como la rotación de un dispositivoFragment
, recibe inmediatamente los últimos datos disponibles. -
Compartir recurso
Puede usar el patrón singleton para extender
LiveData
objetos para encapsular servicios del sistema para que puedan compartirse entre aplicaciones.LiveData
El objeto se conecta al servicio del sistema una vez, y luego cualquier observador que necesite el recurso correspondiente simplemente observaLiveData
el objeto.
3. Usa el objeto LiveData
Siga los pasos a continuación para usar LiveData
el objeto:
-
Se crea una instancia de
LiveData
para almacenar algún tipo de datos. Esto generalmenteViewModel
se hace en las clases. -
Crea un objeto
onChanged()
que defineObserver
un método que controlaLiveData
lo que sucede cuando cambian los datos almacenados por el objeto. Por lo general, los objetos se creanObserver
en un controlador de interfaz, como una Actividad o un Fragmento. -
Utilice
observe()
el método paraObserver
adjuntar el objeto alLiveData
objeto.observe()
El método tomaLifecycleOwner
un objeto. Esto hace queObserver
el objeto se suscriba alLiveData
objeto para que se le notifiquen los cambios. Por lo general, adjuntaObserver
objetos en un controlador de interfaz, como una actividad o un fragmento.Nota : Puede utilizar
observeForever(Observer)
el método para registrar un observador sin unLifecycleOwner
objeto asociado. En este caso, se considera que el observador está siempre activo, por lo que siempre se le notifican las modificaciones. PuederemoveObserver(Observer)
eliminar estos observadores llamando al método.
Cuando actualiza LiveData
el valor almacenado en el objeto, activa todos los observadores registrados (siempre que el adjunto LifecycleOwner
esté activo).
LiveData
Permite que los observadores del controlador de IU se suscriban a las actualizaciones. Cuando LiveData
los datos en el almacén de objetos cambian, la interfaz se actualiza automáticamente para responder.
-
crear
LiveData
objetoLiveData
es un contenedor que se puede usar para cualquier dato, incluidosCollections
los objetos que implementan, comoList
.LiveData
Los objetos normalmente se almacenan enViewModel
objetos 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,
LiveData
los datos en el objeto no están configurados.
Nota : asegúrese de que LiveData
el objeto utilizado para actualizar la interfaz ViewModel
esté 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 LiveData
la instancia de una instancia específica de Actividad o Fragmento y permita que LiveData
el objeto sobreviva a los cambios de configuración
-
LiveData
objeto de observaciónEn la mayoría de los casos,
onCreate()
el método de aplicación de un componente esLiveData
el 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
STARTED
estado, recibe el valor más reciente del objeto que está observandoLiveData
.LiveData
Esto 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
LiveData
objetos: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); } }
nameObserver
Cuando se llama con el parámetro pasadoobserve()
, se llama inmediatamenteonChanged()
, proporcionandomCurrentName
el último valor almacenado en el archivo . No se llamará siLiveData
el objeto aún no tiene un valor establecido en .mCurrentName
onChanged()
- Asegúrese de que el sistema no realice llamadas redundantes desde
-
actualizar
LiveData
objetoLiveData no tiene métodos disponibles públicamente para actualizar los datos almacenados.
MutableLiveData
La clase expondrá métodos, que deben usarsesetValue(T)
sipostValue(T)
necesita modificar el valor almacenado en el objeto.LiveData
Normalmente se usaríaViewModel
enMutableLiveData
, luegoViewModel
solo exponeLiveData
objetos inmutables a los observadores.Después de configurar las relaciones de los observadores, puede actualizar
LiveData
el 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 Doe
llame 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 LiveData
el objeto desde el hilo principal. Si ejecuta código en un subproceso de trabajo, puede usar postValue(T)
el método para actualizar LiveData
el objeto en su lugar.
-
Usar
LiveData
con HabitaciónLa biblioteca de persistencia de Room admite
LiveData
consultas 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
LiveData
todo 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
LiveData
Tiene 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, fragment
usando 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.LiveData
ViewModel
ViewModel
LiveData
ViewModel
LiveData
activity
y fragment
no deben persistir LiveData
instancias 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 LiveData
no es adecuado para manejar flujos de datos asíncronos. Si bien puede usar LiveData
transformaciones MediatorLiveData
para lograrlo, las desventajas de este enfoque son que existe una funcionalidad muy limitada para combinar flujos de datos y todos los LiveData
objetos (incluidos los creados por transformaciones) se observan en el subproceso principal. Aquí hay un código de muestra que muestra cómo Repository
retener en LiveData
un 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 .ViewModel
LiveData
Flow
LiveData
RxJava
5. Ampliar LiveData
Un observador se considera activo si su tiempo de vida se encuentra en el estado STARTED
o . El siguiente código de ejemplo ilustra cómo extender una clase:RESUMED
LiveData
LiveData
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:
LiveData
El método se llama cuando el objeto tiene observadores activosonActive()
. Eso significa que debe comenzar a ver las actualizaciones del precio de las acciones desde este método.LiveData
El método se llama cuando el objeto no tiene ningún observador activoonInactive()
. Dado que no hay observadores escuchando, no hay razónStockManager
para mantener una conexión con el servicio.setValue(T)
El método actualizaráLiveData
el valor de la instancia y notificará a los observadores activos del cambio.
Puedes usar StockLiveData
la 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 Fragment
la vista asociada LifecycleOwner
como primer parámetro. Si lo hace, indica que este observador está vinculado al objeto asociado con el propietario Lifecycle
, lo que significa:
- Si
Lifecycle
el objeto no está vivo, no se llamará al observador aunque cambie el valor. Lifecycle
Los observadores se eliminan automáticamente cuando se destruye el objeto.
LiveData
El hecho de que los objetos sean conscientes del ciclo de vida significa que puede compartir estos objetos entre múltiples Activity
y Fragment
. Service
Para simplificar el ejemplo, puede LiveData
implementar 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 Fragment
usarlo 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 Fragment
y Activity
observables . Solo conéctese a MyPriceListener
uno o más servicios del sistema si están visibles y activos .LiveData
6. Convertir datos en vivo
Es posible que desee LiveData
realizar cambios en los valores almacenados en el objeto antes de enviarlo a los observadores, o es posible que deba devolver una LiveData
instancia diferente en función del valor de otra instancia. Lifecycle
El paquete proporciona Transformations
la 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 enLiveData
el objeto y desempaqueta y envía el resultado aguas abajo. Una función pasadaswitchMap()
a debe devolverLiveData
un 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. LiveData
Las 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 ViewModel
necesita Lifecycle
un 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 LiveData
objeto 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, postalCode
los campos se definen como addressInput
transformaciones de . Siempre que su aplicación tenga postalCode
un observador activo asociado con el campo, el valor del campo se addressInput
recalculará 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
. ViewModel
Los objetos pueden obtener fácilmente LiveData
referencias a objetos y luego definir reglas de transformación basadas en ellos.
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 MediatorLiveData
la clase, que escucha otros LiveData
objetos y maneja los eventos emitidos por ellos. MediatorLiveData
Propaga su estado al LiveData
objeto de origen correctamente. Para obtener más información sobre este patrón, consulte Transformations
la documentación de referencia de la clase.
7. Combinar múltiples fuentes de LiveData
MediatorLiveData
Es LiveData
una subclase que le permite combinar múltiples LiveData
fuentes. LiveData
El 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 MediatorLiveData
agregar 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 MediatorLiveData
puede recibir actualizaciones de ambas fuentes simplemente observando el objeto.