web-dev-qa-db-fra.com

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.

28
Reza A. Ahmadi

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

34
Abhishek V

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}"
        />
11
sonique

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
});
0
florian-do