Обновление LiveData при изменении поля объекта
Я использую архитектуру Android MVVM с LiveData. У меня есть такой объект
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;
}
}
И моя модель выглядит так:
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 ");
}
}
Как я могу убедиться, что некоторые зарегистрированные в пользовательских объектах изменения наблюдателей получают уведомление? Кстати, мне важно хранить эти данные в отдельном объекте и не использовать первичные значения, такие как строки в моей модели ViewModel.
Ответы
Ответ 1
Я не думаю, что есть какая-то лучшая практика, рекомендованная андроидом для этого. Я предлагаю вам использовать подход, который использует более чистый и менее шаблонный код.
Если вы используете привязку данных к файлам android вместе с LiveData
, вы можете использовать следующий подход:
Ваш объект POJO будет выглядеть примерно так.
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);
}
}
Итак, у вас уже будет класс, который уведомляет о каждом изменении его свойства. Таким образом, вы можете просто использовать этот обратный вызов изменения свойств в своей MutableLiveData, чтобы уведомить своего наблюдателя. Вы можете создать пользовательскую MutableLiveData для этого
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());
}
};
}
Затем все, что вам нужно сделать, это использовать эту CustomMutableLiveData вместо MutableLiveData в вашей модели просмотра
public class InfoViewModel extends AndroidViewModel {
CustomMutableLiveData<User> user = new CustomMutableLiveData<>();
-----
-----
Таким образом, делая это, вы можете уведомить обозревателя просмотра и LiveData с небольшим изменением существующего кода. Надеюсь, что это поможет.
Ответ 2
При использовании MVVM и LiveData вы можете повторно привязать объект к макету, чтобы он вызвал все изменения в пользовательском интерфейсе.
Данный "пользователь" является MutableLiveData<User>
в 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()
}
}
Файл активности/фрагмента:
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
})
Ваш файл макета не должен меняться:
<data>
<variable
name="user"
type="com.project.model.User" />
</data>
...
<TextView
android:id="@+id/firstname"
android:text="@{user.firstname}"
/>
Ответ 3
Чтобы ваш наблюдатель получил уведомление, вы должны использовать setValue
, если вы это сделаете
user.getValue().setFirstName(user.getValue().getFirstName() + " A ");
ваш наблюдатель не будет уведомлен!
Просмотр модели
public MutableLiveData<User> getUser() {
return user;
}
Активность/фрагмент
mModel = ViewModelProviders.of(this).get(InfoViewModel.class);
mModel.getUser().observe(this, s -> {
// User has been modified
});
Где-то в вашей деятельности/фрагменте
Это вызовет наблюдателя:
mModel.getUser().setValue(user);
Если вы хотите обновить только одно поле от объекта вместо обновления всего объекта, у вас должны быть кратные 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
});
Ответ 4
Я отправил тот же вопрос, и я получил самое простое решение. Найдите мой ответ здесь