72 votes

LiveData mise à jour sur l'objet de changement de champ

Je suis sur 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 de mon point de vue, le modèle 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 lorsque certains déposée dans l'objet utilisateur des modifications des observateurs être averti? BTW, il est important pour moi de conserver ces données dans le séparer de l'objet et de ne pas utiliser ces valeurs comme des Cordes à mon ViewModel.

63voto

Abhishek V Points 6643

Je ne pense pas qu'il y est de bonnes pratiques en tant que telles recommandé par android pour cela. Je vous suggère d'utiliser l'approche qui utilise la plus propre et moins de code réutilisable.

Si vous utilisez android liaison de données avec LiveData vous pouvez aller avec la méthode suivante:

Votre POJO objet ressemblerait à quelque chose comme ceci

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);
    }
}

Si vous seriez déjà avoir une classe qui informe chaque fois que des modifications de la propriété. Ainsi, vous pouvez simplement faire usage de ce changement de propriété de rappel dans votre MutableLiveData de notifier à son observateur. Vous pouvez créer un MutableLiveData pour cette

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 devez faire est d'utiliser cette 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 informer à la fois de la vue & LiveData observateur avec peu de changement de code existant. J'espère que ça aide

26voto

sonique Points 87

Lors de l'utilisation de MVVM et LiveData, vous pouvez re-lier l'objet à la mise en page de sorte qu'il va déclencher toutes les modifications apportées à l'INTERFACE utilisateur.

Compte tenu de "l'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()
    }
}

Activité/Fragment de fichier:

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

0voto

florian-do Points 521

Pour votre observateur averti, vous devez utiliser setValue si vous faites cela, user.getValue().setFirstName(user.getValue().getFirstName() + " A "); votre observateur ne sera pas informé !

Modèle De Vue

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 va déclencher l'observateur :

mModel.getUser().setValue(user);

Si vous souhaitez mettre à jour un champ à partir d'un objet au lieu de le mettre à jour l'ensemble de l'objet, vous devriez avoir de 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
});

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X