so I'm coming from an MVP background... What I'm basically trying to do is start a loadingView as soon as we start fetching the data from Room (SQLite), stop the loadingView when successful and all of that logic should be handled in my ViewModel (trying to keep my fragment clean) class for the Fragment.
What I've done right now is that I've got two LiveData's:
Here's what I mean:
enum HomeState{
LOADING,
LIVE
}
private LiveData<List<SomeData>> someData;
private MutableLiveData<HomeState> homeState;
I'm observing both in my fragment and I want to have my homeStateLiveData determine whether the fragment should be displaying a loading view.. As you can probably see, this won't work as when the new data comes it immediately goes to the fragment and I can't control the homeState logic from the ViewModel
The observe() method takes a LifecycleOwner object. This subscribes the Observer object to the LiveData object so that the observer is notified of changes. You usually attach the Observer object in a UI controller, such as an activity or fragment.
No, It is not mandatory to use LiveData always inside ViewModel, it is just an observable pattern to inform the caller about updates in data.
Up until now, we've used Data Binding to update the View from the ViewModel. LiveData is a handy data holder that acts as a container over the data to be passed. The best thing about LiveData is that it is lifecycle aware. So if you are in the background, the UI won't try to update.
As you can probably see, this won't work as when the new data comes it immediately goes to the fragment and I can't control the homeState logic from the ViewModel
You can control the homeState based on the database LiveData by putting yourself between the fragment's observer and the database's LiveData. The way you would do this would be either through a Transformation or through a MediatorLiveData.
// with a Transformation
// this would be the method which returns the database LiveData
public LiveData<List<SomeData>> getDatabaseData() {
// the view should show a loading indicator
homeState.setValue(HomeState.LOADING);
// we don't actually map anything, we just use the map function to get
// a callback of when the database's LiveData has finished loading
return Transformations.map(dao.getSomeData(), list -> {
// the database has just finished fetching the data from the database
// and after this method returns it will be available to the observer
// in the fragment.
// we also need to dismiss the loading indicator
homeState.setValue(HomeState.LIVE);
return list;
});
}
With a MediatorLiveData you would do something similar, just make the MediatorLiveData listen for the database LiveData and update the homeState in the observer it sets when you add the database LiveData as its source.
If you want to abstract this, you could wrap the data you get from the database and the state(loading or available) into a single class and change your ViewModel to only return a LiveData with that class. The architecture components guide has an example(kind of related) on how you may do this, there they monitor the status of the network but you could easily adapt this to your database scenario.
I am using loading state in mvvm
, rx
, kotlin
, retorfit
for recyclerview
.
Here is my actual loading state.
Here is my binding adapter for observe loading state.
Here is my extended recyclerview
class for loading state and empty view.
Here is my xml file for bind loading state.
Maybe you can get inspiration from my example.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With