I am working with Firestore and successfully integrated it with Paging Library using ItemKeyedDataSource
. Here is a gist:
public class MessageDataSource extends ItemKeyedDataSource<Query, Message> {
//... private members
MessageDataSource(Query query) {
mQuery = query;
}
@Override
public void loadInitial(@NonNull LoadInitialParams<Query> params, @NonNull LoadInitialCallback<Message> callback) {
mLoadStateObserver.postValue(LoadingState.LOADING);
mQuery.limit(params.requestedLoadSize).get()
.addOnCompleteListener(new OnLoadCompleteListener() {
@Override
protected void onSuccess(QuerySnapshot snapshots) {
getLastDocument(snapshots);
// I'm able to get the values here
List<Message> m = snapshots.toObjects(Message.class);
for (Message message : m) {
Log.d(TAG, "onSuccess() returned: " + message.getTitle());
}
callback.onResult(snapshots.toObjects(Message.class));
}
@Override
protected void onError(Exception e) {
Log.w(TAG, "loadInitial onError: " + e);
}
});
}
@Override
public void loadAfter(@NonNull LoadParams<Query> params, @NonNull LoadCallback<Message> callback) {
Log.d(TAG, "LoadingState: loading");
mLoadStateObserver.postValue(LoadingState.LOADING);
params.key.limit(params.requestedLoadSize).get()
.addOnCompleteListener(new OnLoadCompleteListener() {
@Override
protected void onSuccess(QuerySnapshot snapshots) {
getLastDocument(snapshots);
callback.onResult(snapshots.toObjects(Message.class));
}
@Override
protected void onError(Exception e) {
Log.w(TAG, "loadAfter onError: " + e);
}
});
}
private void getLastDocument(QuerySnapshot queryDocumentSnapshots) {
int lastDocumentPosition = queryDocumentSnapshots.size() - 1;
if (lastDocumentPosition >= 0) {
mLastDocument = queryDocumentSnapshots.getDocuments().get(lastDocumentPosition);
}
}
@Override
public void loadBefore(@NonNull LoadParams<Query> params, @NonNull LoadCallback<Message> callback) {}
@NonNull
@Override
public Query getKey(@NonNull Message item) {
return mQuery.startAfter(mLastDocument);
}
/*
* Public Getters
*/
public LiveData<LoadingState> getLoadState() {
return mLoadStateObserver;
}
/* Factory Class */
public static class Factory extends DataSource.Factory<Query, Message> {
private final Query mQuery;
private MutableLiveData<MessageDataSource> mSourceLiveData = new MutableLiveData<>();
public Factory(Query query) {
mQuery = query;
}
@Override
public DataSource<Query, Message> create() {
MessageDataSource itemKeyedDataSource = new MessageDataSource(mQuery);
mSourceLiveData.postValue(itemKeyedDataSource);
return itemKeyedDataSource;
}
public LiveData<MessageDataSource> getSourceLiveData() {
return mSourceLiveData;
}
}
}
And then within MessageViewModel
class's constructor:
MessageViewModel() {
//... Init collections and query
// Init Paging
MessageDataSource.Factory mFactory = new MessageDataSource.Factory(query);
PagedList.Config config = new PagedList.Config.Builder()
.setPrefetchDistance(10)
.setPageSize(10)
.setEnablePlaceholders(false)
.build();
// Build Observables
mMessageObservable = new LivePagedListBuilder<>(mFactory, config)
.build();
mLoadStateObservable = Transformations.switchMap(mMessageObservable, pagedListInput -> {
// No result here
Log.d(TAG, "MessageViewModel: " + mMessageObservable.getValue());
MessageDataSource dataSource = (MessageDataSource) pagedListInput.getDataSource();
return dataSource.getLoadState();
});
}
Note the situation:
When I'm initializing the viewmodel in
MainActivity#oncreate
method and observing it, it is working as intended and is able to view it in recyclerview.Later I decided to create a Fragment and refactored it by moving all the logic to the Fragment and when I try to observe the same livedata, no values are returned. Here's how I doing it.
Within Fragment:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
mViewModel = ViewModelProviders.of(getActivity()).get(MessageViewModel.class);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//...
mViewModel.getMessageObserver().observe(this, messages -> {
Log.d(TAG, "onCreateView() returned: " + messages.size());
});
mViewModel.getLoadingStateObserver().observe(this, loadingState -> {
Log.d(TAG, "onCreateView() returned: " + loadingState.name());
});
return view;
}
The interesting part:
- Within the Fragment the
loadstate
is returning the valuesLOADING
andSUCCESS
- Within
MessageDataSource
, values of the query is successfully returned but while observing the same in the Fragment, I get no values.
What am I doing wrong here?
P.S: I'm learning Android.