I\'ve been unable to create an Android Architecuture Components ViewModel that composes multiple LiveData models into one LiveData class for my Fragment to observe. I want t
I would suggest to take a different approach:
lifecycle-reactivestreams
from the Architecture Components.By using RxJava you can easily merge observables together and only expose that combination to the view using LiveData
. I would recommend to use LiveData
only to expose state to the view (Fragment
or Activity
).
I wrote an article on how to do this. You might find it useful.
Hope my work satisfy your question.
I have made a sample project before and now integrate another fake livedata into this view model. Difference of the file
Use MediatorLiveData class to wrap multi data source to one.
FeedEntryListViewModel.java
public class FeedEntryListViewModel extends ViewModel {
//list all your live data here
private LiveData<List<FeedEntry>> feedEntries = new MutableLiveData<>();
private MutableLiveData<String> userId = new MutableLiveData<>();
//show your composite model here
private MediatorLiveData<CompositeModel> compositeModelLiveData;
//list all your repository
private FeedEntryRepository feedEntryDBRepository;
/*
The complete model to show the data
*/
public static class CompositeModel {
String userId = "SystemId";
private List<FeedEntry> feedEntries = new ArrayList<>();
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public List<FeedEntry> getFeedEntries() {
return feedEntries;
}
public void setFeedEntries(
List<FeedEntry> feedEntries) {
this.feedEntries = feedEntries;
}
}
public FeedEntryListViewModel(
FeedEntryRepository feedEntryDBRepository) {
this.feedEntryDBRepository = feedEntryDBRepository;
this.feedEntries = feedEntryDBRepository.getAll();
this.compositeModelLiveData = new MediatorLiveData<>();
this.compositeModelLiveData.addSource(feedEntries, data ->
{
CompositeModel compositeModel = compositeModelLiveData.getValue();
compositeModel.setFeedEntries(data);
compositeModelLiveData.postValue(compositeModel);
});
this.compositeModelLiveData.addSource(userId, data -> {
CompositeModel compositeModel = compositeModelLiveData.getValue();
compositeModel.setUserId(data);
compositeModelLiveData.postValue(compositeModel);
});
//initialize the composite model to avoid NullPointerException
this.compositeModelLiveData.postValue(new CompositeModel());
}
public void loadUserId(String userId) {
this.userId.setValue(userId);
}
public LiveData<List<FeedEntry>> getFeedEntrys() {
return feedEntryDBRepository.getAll();
}
public LiveData<CompositeModel> getCompositeEntrys() {
return compositeModelLiveData;
}
public LiveData<List<FeedEntry>> insert(FeedEntry... feedEntries) {
feedEntryDBRepository.insertAll(feedEntries);
return feedEntryDBRepository.getAll();
}
public void delete(FeedEntry feedEntry) {
feedEntryDBRepository.delete(feedEntry);
}
public int update(FeedEntry feedEntry) {
return feedEntryDBRepository.update(feedEntry);
}
}
In the Activity, you still can get the composite with the statement
viewModel.getCompositeEntrys().observe(this, entries -> {...});
View Model Constructor add the live data and bind to the composite live data
public FeedEntryListViewModel(
FeedEntryRepository feedEntryDBRepository) {
this.feedEntryDBRepository = feedEntryDBRepository;
this.feedEntries = feedEntryDBRepository.getAll();
this.compositeModelLiveData = new MediatorLiveData<>();
this.compositeModelLiveData.addSource(feedEntries, data ->
{
CompositeModel compositeModel = compositeModelLiveData.getValue();
compositeModel.setFeedEntries(data);
compositeModelLiveData.postValue(compositeModel);
});
this.compositeModelLiveData.addSource(userId, data -> {
CompositeModel compositeModel = compositeModelLiveData.getValue();
compositeModel.setUserId(data);
compositeModelLiveData.postValue(compositeModel);
});
//initialize the composite model to avoid NullPointerException
this.compositeModelLiveData.postValue(new CompositeModel());
}