LiveData update on object field change
Solution 1:
I don't think there is any best practice as such recommended by android for this. I would suggest you to use the approach which uses cleaner & less boilerplate code.
If you are using android data binding along with LiveData
you can go with the following approach:
Your POJO object would look something like this
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);
}
}
So you would be already having a class which notifies whenever its property changes. So you can just make use of this property change callback in your MutableLiveData to notify its observer. You can create a custom MutableLiveData for this
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());
}
};
}
Then all you need to do is use this CustomMutableLiveData instead of MutableLiveData in your View Model
public class InfoViewModel extends AndroidViewModel {
CustomMutableLiveData<User> user = new CustomMutableLiveData<>();
-----
-----
So by doing this you can notify both view & LiveData observer with little change to existing code. Hope it helps
Solution 2:
When using MVVM and LiveData, you can re-bind the object to the layout so it will trigger all changes on the UI.
Given "user" is a MutableLiveData<User>
in the 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()
}
}
Activity/Fragment file:
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 = it //<- re-binding user
})
Your layout file shouldn't change:
<data>
<variable
name="user"
type="com.project.model.User" />
</data>
...
<TextView
android:id="@+id/firstname"
android:text="@{user.firstname}"
/>