Reputation: 533
I am looking for recommendation in handling below use case w.r.t. LiveData handling: ViewModel invokes Repository for LiveData (e.g. products catalog). Repository checks from LocalDataSource(Room) first but if data not available, invokes RemoteDataSource(REST API).
Questions:
1) As per below comment from yigit here, Repository can't get LiveData availability status in Room until it subscribes as observer. So even when data is avaiable, I get null in response. "LiveData is to watch the data and distribute it to the observers. It won't calculate the value until an active observer is added."
Since Repository hides data sources to clients, it is repository's responsibility to check in Room and then pull from Remote Source. How can it check for data availability in Room ?
2) Since data returned by RemoteDataSource is not LiveData type, what should be done so that repository eventually returns LiveData to ViewModel ?
Should Repository first insert data (from RemoteDataSource) into Room first and then query Room so it returns LiveData ? It looks quite expensive operation as there Room is queried twice in the process. Please advise . Thanks !
Upvotes: 3
Views: 3633
Reputation: 533
Firstly, thanks to @adityakamble49 for answering to my question, credit goes to him ! You can maintain abstraction using Repository by giving LiveData as return value and using NetworkBoundResource you can decide if you need to fetch from Network or you can use cached data (DB / DataHolder). NetworkBoundResource is a clean way to implement common functionality (using Generics) in abstract class and provide explicit behavior in extended class(es).
Sharing my viewPoint on NetworkBoundResource class vs android-priority-jobqueue so it helps us decide which one to use in vairous scenarios.
NetworkBoundResource - Use when app need to fetch data from local DB or network but also display error to user when fetch fails (e.g. no network). Pull to Refrsh on a screen is a good use case where user expects to see updated data or otherwise see error toast/dialog if fetch fails.
android-priority-jobqueue - There are many scenarios when an action need to be preserved until it completes successfully (rather than display error and forget). JobQueue helps a lot in such scenarios to maintain pending jobs (for associated triggers) in background queue and later process them when network is avialable. E.g. A note created by user in offline mode is added to JobQueue which gets synched later when device comes online. Such scenario can't be addressed with NetworkBoundResource.
A NetworkBoundResource candidate operation shouldn't be handled using JobQueue (and vice versa) as it could flood the JobQueue with too many operations and many of them could be duplicate e.g. multiple Pull To Refresh actions on same screen leading to multiple Jobs, which is wrong. Welcoming others viewpoints !!!
Upvotes: 2
Reputation: 2011
I would recommend to insert Data in Database first and observe that as LiveData using Room. You will need to observe database using LiveData provided by Room, and update REST API response in database from Repository.
You need to use ViewModel to hold all LiveData objects observed from database in your Activity / Fragment.
To check for data availability in Room use NetworkBoundResource
class which they have provided in Android Architecture component guidelines from here.
But if you feel this operation expensive and don't want to store every data in database for instance, then create simple LiveData variable in some DataHolder class using MutableLiveData.
public class DataHolder {
// Create a LiveData using MutableLiveData
private LiveData<String> data;
public LiveData<String> getData() {
if (data == null) {
data = new MutableLiveData<String>();
}
return data;
}
public void updateData(String value) {
data.setValue(value);
}
}
DataHolder is not ViewModel in this case as updating upper layer component directly from lower layer component is not recommended. Refer to this diagram for details Android Architecture Components
In repository's getData()
method call the getData()
from DataHolder. Basically wrap that method to make abstraction for upper layer.
Update that LiveData variable from RestAPI response using setValue(T)
and postValue(T)
as show in updateData() wrapper.
Upvotes: 1