Reputation: 2124
I'm having a good problem trying to paginate datas from firebase database for weeks now all to no avail. I tried all the example from android documentation to SO not still working. Below is a screenshot of my data node
Below is my code, I'm using recycleview for continous scrolling.
commentDatabaseReference = FirebaseDatabase.getInstance().getReference().child(CHANNEL_COMMENT).child(postId);
commentDatabaseReference.orderByKey().limitToLast(TOTAL_ITEM_EACH_LOAD).addListenerForSingleValueEvent(commentValueEventListener);
ValueEventListener commentValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChildren()) {
currentPage--;
}
int counter = 0;
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
commentId = snapshot.getKey();
Comment comment = snapshot.getValue(Comment.class);
commentList.add(comment);
adapter.notifyDataSetChanged();
}
//adapter.notifyDataSetChanged();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
Recycleview continous scrolling listener
recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
Log.e("more", "onload");
loadMoreData();
}
});
private void loadData() {
Log.e("loading", ""+ commentId);
commentDatabaseReference.orderByChild("timestamp").startAt(commentId).limitToLast(TOTAL_ITEM_EACH_LOAD)
.addListenerForSingleValueEvent(commentValueEventListener);
}
private void loadMoreData(){
//if ((currentPage * TOTAL_ITEM_EACH_LOAD) <= commentCount) {
currentPage++;
loadData();
//}
}
Conclusion: For instance if I have 20 data with offset of 10 and I use orderby with limitToLast I get the last 10 data starting at the top i.e I get data from 11 - 20 instead of 20 - 11. Also noticed sometimes I get unending data when I combine with startAt
Upvotes: 2
Views: 3344
Reputation: 2124
Finally solved this thanks to faruk hints:
The code below methods load data from firebase to the recycleview
private void loadData() {
Query query;
if (commentId == null) {
query = commentDatabaseReference.orderByChild("timestamp").limitToLast(TOTAL_ITEM_EACH_LOAD);
} else {
query = commentDatabaseReference.orderByChild("timestamp").startAt(inverseTimestamp).limitToFirst(TOTAL_ITEM_EACH_LOAD);
}
query.addListenerForSingleValueEvent(commentValueEventListener);
}
private void loadMoreData(){
//commentCount: is the total comments stored in firebase database
if ((currentPage * TOTAL_ITEM_EACH_LOAD) <= commentCount) {
currentPage++;
loadData();
}
}
On the recycleview scroll listener i called loadMoreData method to fetch more data from firebase
recyclerView.addOnScrollListener(new EndlessRecyclerOnScrollListener(linearLayoutManager) {
@Override
public void onLoadMore(int page, int totalItemsCount, RecyclerView view) {
//Load more data
loadMoreData();
}
});
Firebase database listener to listen to data fetched
ValueEventListener commentValueEventListener = new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
if(!dataSnapshot.hasChildren()) {
currentPage--;
}
int counter = 0;
for (DataSnapshot snapshot : dataSnapshot.getChildren()) {
commentId = snapshot.getKey();//Index key for the node
Comment comment = snapshot.getValue(Comment.class);
++counter;
//Inverse timestamp
inverseTimestamp = comment.getTimestamp();
//store nth - 1 data into the arraylist to avoid duplicates
if (counter < TOTAL_ITEM_EACH_LOAD) {
commentList.add(comment);
adapter.notifyDataSetChanged();
}
}
//adapter.notifyDataSetChanged();
}
@Override
public void onCancelled(DatabaseError databaseError) {
}
};
Upvotes: 3
Reputation: 5841
Use limitToFirst
and add a field (timestamp inverse) that contains timestamp * -1
for example call it timestampInv
And then you can orderByChild("timestampInv")
and startAt
:
commentDatabaseReference
.orderByChild("timestampInv")
.startAt(lastTimeInv)
.limitToFirst(TOTAL_ITEM_EACH_LOAD)
.addListenerForSingleValueEvent(commentValueEventListener);
If you want to create the timestamp inverse automatically, I suggest using cloud function
with onCreate
trigger :
exports.addCommentTimestampInv = functions.database.ref('/comment/{postId}/{commentId}')
.onCreate(event => {
// Grab the current value of what was written to the Realtime Database.
const commentData = event.data.val();
var timeInv = commentData.timestamp * -1;
return event.data.ref.child('timestampInv').set(timeInv);
});
Hope it helps :)
Upvotes: 1