LiveData mise à jour sur le changement de champ d'objet
J'utilise Android Architecture MVVM avec LiveData. J'ai un objet comme celui-ci
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;
}
}
Et mon modèle de vue ressemble à ceci
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 ");
}
}
Comment puis-je m'assurer que certains observateurs enregistrés dans les modifications d'objet utilisateur sont avertis? BTW il est important pour moi de conserver ces données dans l'objet séparé et de ne pas utiliser de valeurs primaires telles que Strings dans mon ViewModel.
Je ne pense pas qu'il existe de meilleure pratique en tant que telle recommandée par Android pour cela. Je vous suggérerais d'utiliser l'approche qui utilise du code plus propre et moins inchangé.
Si vous utilisez la liaison de données Android avec LiveData
, vous pouvez utiliser l'approche suivante:
Votre objet POJO ressemblerait à quelque chose comme ça
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);
}
}
Donc, vous auriez déjà une classe qui notifie chaque fois que sa propriété change. Vous pouvez donc simplement utiliser ce rappel de modification de propriété dans votre MutableLiveData pour avertir son observateur. Vous pouvez créer un MutableLiveData personnalisé pour cela.
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());
}
};
}
Ensuite, tout ce que vous avez à faire est d’utiliser ce CustomMutableLiveData au lieu de MutableLiveData dans votre modèle de vue.
public class InfoViewModel extends AndroidViewModel {
CustomMutableLiveData<User> user = new CustomMutableLiveData<>();
-----
-----
En faisant cela, vous pouvez notifier à la fois View & LiveData Observer en apportant peu de modifications au code existant. J'espère que ça aide
Lorsque vous utilisez MVVM et LiveData, vous pouvez relier l'objet à la présentation afin qu'il déclenche toutes les modifications sur l'interface utilisateur.
Étant donné que "utilisateur" est un MutableLiveData<User>
dans le 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()
}
}
Fichier d'activité/fragment:
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
})
Votre fichier de mise en page ne devrait pas changer:
<data>
<variable
name="user"
type="com.project.model.User" />
</data>
...
<TextView
Android:id="@+id/firstname"
Android:text="@{user.firstname}"
/>
Pour que votre observateur soit averti, vous devriez utiliser setValue
si vous faites cela user.getValue().setFirstName(user.getValue().getFirstName() + " A ");
, votre observateur ne sera pas averti!
Voir le modèle
public MutableLiveData<User> getUser() {
return user;
}
Activité/Fragment
mModel = ViewModelProviders.of(this).get(InfoViewModel.class);
mModel.getUser().observe(this, s -> {
// User has been modified
});
Quelque part dans votre activité/fragment
Cela déclenchera l'observateur:
mModel.getUser().setValue(user);
Si vous souhaitez mettre à jour un seul champ à partir d'un objet au lieu de mettre à jour tout l'objet, vous devez avoir des multiples 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
});