I have a situation where I have a view model for a page that is rendered based on some input data (id) with fields that are initialized from my repository but can be edited by the user.
My repository function is pretty straightforward:
class AccountsRepository {
public LiveData<Account> getAccount(long id) {
return roomDb.accountDao().getAccount(id);
}
}
I want my view model to be re-used for different accounts so I have a LiveData<Long>
that will be set with the account ID.
class EditAccountViewModel {
private MutableLiveData<Long> accountId = new MutableLiveData<>();
public void setAccountId(long id) {
accountId.setValue(id);
}
}
In my view model, I want to expose a mutable field name
that will be bound to an EditText
view. This field should be initialized by the data in the repository. If I use a simple non-editable binding, I am able to get one-way databinding working:
class EditAccountViewModel {
private MutableLiveData<Long> accountId = new MutableLiveData<>();
public LiveData<String> name;
EditAccountViewModel() {
this.name = Transformations.map(
Transformations.switchMap(accountId, repo::getAccount),
account -> account.name);
}
}
However, I cannot bind this using @={viewModel.name}
because it complains that it does not know how to set the value. I tried writing a helper class like so that uses an underlying MediatorLiveData
to set the value, but it looks like my onChanged callback is never called:
class MutableLiveDataWithInitialValue<T> extends MutableLiveData<T> {
MutableLiveDataWithInitialValue(LiveData<T> initialValue) {
MediatorLiveData<T> mediator = new MediatorLiveData<>();
mediator.addSource(
initialValue,
data -> {
// This never gets called per the debugger.
mediator.removeSource(initialValue);
setValue(data);
});
}
}
I updated the view model as follows:
class EditAccountViewModel {
private MutableLiveData<Long> accountId = new MutableLiveData<>();
public MutableLiveData<String> name;
EditAccountViewModel() {
this.name = new MutableLiveDataWithInitialValue<>(
Transformations.map(
Transformations.switchMap(accountId, repo::getAccount),
account -> account.name));
}
}
However, when I do this my EditText
field never sets the value from the database, and this makes sense because the onChanged
callback is never called in my MediatorLiveData
in MutableLiveDataWithInitialValue
.
This seems like a pretty common use case, so I'm wondering what I am screwing up?