android - example - Actualización de LiveData en cambio de campo de objeto
mutablelivedata (3)
Estoy usando la arquitectura MVVM de Android con LiveData. Tengo un objeto como este
public class User {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Y mi modelo de vista se ve así
public class InfoViewModel extends AndroidViewModel {
MutableLiveData<User> user = new MutableLiveData<>();
public InfoViewModel(@NonNull Application application) {
super(application);
User user = new User();
user.setFirstName("Alireza");
user.setLastName("Ahmadi");
this.user.setValue(user);
}
public LiveData<User> getUser(){
return user;
}
public void change(){
user.getValue().setFirstName(user.getValue().getFirstName() + " A ");
}
}
¿Cómo puedo asegurarme de que cuando se notifique a algunos observadores de cambios de objeto de usuario? Por cierto, es importante para mí mantener estos datos en el objeto separado y no usar valores primarios como cadenas en mi ViewModel.
Al usar MVVM y LiveData, puede volver a enlazar el objeto con el diseño para que active todos los cambios en la interfaz de usuario.
Dado "usuario" es un MutableLiveData<User>
MutableLiveData en el ViewModel
ViewModel
class SampleViewModel : ViewModel() {
val user = MutableLiveData<User>()
fun onChange() {
user.value.firstname = "New name"
user.value = user.value // force postValue to notify Observers
// can also use user.postValue()
}
}
Archivo de actividad / fragmento:
viewModel = ViewModelProviders
.of(this)
.get(SampleViewModel::class.java)
// when viewModel.user changes, this observer get notified and re-bind
// the user model with the layout.
viewModel.user.observe(this, Observer {
binding.user = viewModel.user //<- re-binding
})
Su archivo de diseño no debe cambiar:
<data>
<variable
name="user"
type="com.project.model.User" />
</data>
...
<TextView
android:id="@+id/firstname"
android:text="@{user.firstname}"
/>
No creo que haya ninguna mejor práctica recomendada por android para esto. Le sugeriría que utilice el método que utiliza un código más limpio y menos repetitivo.
Si está utilizando el enlace de datos de Android junto con LiveData
, puede LiveData
el siguiente enfoque:
Tu objeto POJO se vería así
public class User extends BaseObservable {
private String firstName;
private String lastName;
@Bindable
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
notifyPropertyChanged(BR.firstName);
}
@Bindable
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
notifyPropertyChanged(BR.lastName);
}
}
Por lo tanto, ya estarías teniendo una clase que notifica cada vez que cambia su propiedad. Por lo tanto, solo puede hacer uso de esta devolución de llamada de cambio de propiedad en su MutableLiveData para notificar a su observador. Puede crear un MutableLiveData personalizado para esto
public class CustomMutableLiveData<T extends BaseObservable>
extends MutableLiveData<T> {
@Override
public void setValue(T value) {
super.setValue(value);
//listen to property changes
value.addOnPropertyChangedCallback(callback);
}
Observable.OnPropertyChangedCallback callback = new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
//Trigger LiveData observer on change of any property in object
setValue(getValue());
}
};
}
Entonces todo lo que necesita hacer es usar este CustomMutableLiveData en lugar de MutableLiveData en su modelo de vista
public class InfoViewModel extends AndroidViewModel {
CustomMutableLiveData<User> user = new CustomMutableLiveData<>();
-----
-----
De este modo, puede notificar tanto a view como a LiveData Observer con pocos cambios en el código existente. Espero eso ayude
Para que su observador reciba una notificación, debe usar setValue
si hace esto user.getValue().setFirstName(user.getValue().getFirstName() + " A ");
¡Su observador no será notificado!
Ver modelo
public MutableLiveData<User> getUser() {
return user;
}
Actividad / Fragmento
mModel = ViewModelProviders.of(this).get(InfoViewModel.class);
mModel.getUser().observe(this, s -> {
// User has been modified
});
En algún lugar de tu actividad / fragmento
Esto activará el observador:
mModel.getUser().setValue(user);
Si desea actualizar solo un campo de un objeto en lugar de actualizar todo el objeto, debe tener múltiplos MutableLiveData<String>
// View Model
private MutableLiveData<String> firstName;
private MutableLiveData<String> lastName;
//Somewhere in your code
mModel.getFirstName().setValue(user.getValue().getFirstName() + " A ");
mModel.getFirstName().observe(this, s -> {
// Firstname has been modified
});