Reputation: 73
I am making android chat app with firebase firestore database a I need infinite pagination with listeners for data changes (new massage, deleted massage...)
I found blog post written in kotlin and of corse searched firebase documentation and end up with this code:
// firstTime variable shows if function is called from pagination or initially
private void addMessagesEventListener(boolean firstTime) {
// get collection
CollectionReference messagesCollection = chatsCollection.document(chat.getId()).collection(Constants.FIREBASE_MESSAGES_PATH);
// create query
Query query = messagesCollection.orderBy("timestamp", Query.Direction.DESCENDING);
// if NOT first time add startAt
if (!firstTime) {
query.startAt(startTimestamp);
}
//limit to 20 messages
query.limit(20).get().addOnSuccessListener(queryDocumentSnapshots -> {
if (!firstTime) {
endTimestamp = startTimestamp;
}
startTimestamp = (long) queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1).get("timestamp");
Query innerQuery = messagesCollection.orderBy("timestamp").startAt(startTimestamp);
if(!firstTime) {
innerQuery.endBefore(endTimestamp);
}
ListenerRegistration listener = innerQuery
.addSnapshotListener((queryDocumentSnapshots1, e) -> {
if (e != null) {
Log.w(TAG, "listen:error", e);
return;
}
for (DocumentChange dc : queryDocumentSnapshots1.getDocumentChanges()) {
Message message = dc.getDocument().toObject(Message.class);
switch (dc.getType()) {
case ADDED:
// add new message to list
messageListAdapter.addMessage(message);
if (firstTime) {
messagesList.smoothScrollToPosition(0);
}
break;
case REMOVED:
// remove message from list
messageListAdapter.removeMessage(message);
break;
}
}
});
listeners.add(listener);
});
}
Now, code suppose to save listeners 1st for first 20 messages and new messages, 2nd for messages from 20-40 and so on, but, it is not working for some reason. Am I missing something?
Problem is that line
startTimestamp = (long) queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1).get("timestamp");
gets always the same result. I tried even with documentSnapshot instead of timestamp, same result.
Thanks in advance.
Upvotes: 4
Views: 2162
Reputation: 73
I have found mistake. The working code is:
private void addMessagesEventListener(boolean firstTime) {
CollectionReference messagesCollection = chatsCollection.document(chat.getId()).collection(Constants.FIREBASE_MESSAGES_PATH);
Query query = messagesCollection.orderBy("timestamp", Query.Direction.DESCENDING);
if (!firstTime) {
query = query.startAt(startListen);
}
query.limit(20).get().addOnSuccessListener(queryDocumentSnapshots -> {
if (!firstTime) {
endListen = startListen;
}
startListen = queryDocumentSnapshots.getDocuments().get(queryDocumentSnapshots.size() - 1);
Query innerQuery = messagesCollection.orderBy("timestamp").startAt(startListen);
if(!firstTime) {
innerQuery = innerQuery.endBefore(endListen);
}
ListenerRegistration listener = innerQuery
.addSnapshotListener((queryDocumentSnapshots1, e) -> {
if (e != null) {
Log.w("SASA", "listen:error", e);
return;
}
for (DocumentChange dc : queryDocumentSnapshots1.getDocumentChanges()) {
Message message = dc.getDocument().toObject(Message.class);
switch (dc.getType()) {
case ADDED:
// add new message to list
messageListAdapter.addMessage(message);
if (firstTime) {
messagesList.smoothScrollToPosition(0);
}
break;
case REMOVED:
// remove message from list
messageListAdapter.removeMessage(message);
break;
}
}
});
listeners.add(listener);
});
}
The mistake was in query = query.startAt(startListen)
and innerQuery = innerQuery.endBefore(endListen)
You shoud add
private void detachListeners() {
for(ListenerRegistration registration : listeners) {
registration.remove();
}
}
in onDestroy to detach all listeners.
Code is listening for adding new messages and deleting old ones.
Upvotes: 1
Reputation: 225
try this
@Override
public void onStart() {
super.onStart();
loadFirstQuery();
}
public void loadFirstQuery() {
if (firebaseAuth.getCurrentUser() != null) {
contentListDashboard.clear();
String currentUserId = firebaseAuth.getCurrentUser().getUid();
// what we do when recycler reach bottom
recyclerProfileDashboard.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
// horizontal
//Boolean reachBottom = !recyclerView.canScrollHorizontally(-1);
// for vertical recycler
Boolean reachBottom = !recyclerView.canScrollVertically(-1);
if (reachBottom) {
loadMorePost(); // do load more post
}
}
});
// RETRIEVING FIRST Query
Query firstQuery = firebaseFirestore
.collection("ProfileDashboard")
.document(currentUserId)
.collection("ProfileInfo")
.orderBy("timestamp", Query.Direction.DESCENDING)
.limit(20);
firstQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (!documentSnapshots.isEmpty()) {
// please add if doc not empty
if (isFirstPageFirstLoad) {
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1); // array 0, 1, 2
}
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
//String postId = doc.getDocument().getId();
contentProfileDashboard = doc.getDocument().toObject(ContentProfileDashboard.class);
// if first page firest load true
if (isFirstPageFirstLoad) {
contentListDashboard.add(contentProfileDashboard);
} else {
contentListDashboard.add(0, contentProfileDashboard);
}
// fire the event
adapterProfileDashboard.notifyDataSetChanged();
}
}
isFirstPageFirstLoad = false;
}
}
});
}
}
// Method to load more post
public void loadMorePost() {
if (firebaseAuth.getCurrentUser() != null) {
String currentUserId = firebaseAuth.getCurrentUser().getUid();
Query nextQuery = firebaseFirestore
.collection("ProfileDashboard")
.document(currentUserId)
.collection("ProfileInfo")
.orderBy("timestamp", Query.Direction.DESCENDING)
.startAfter(lastVisible)
.limit(20);
nextQuery.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(QuerySnapshot documentSnapshots, FirebaseFirestoreException e) {
if (!documentSnapshots.isEmpty()) {
lastVisible = documentSnapshots.getDocuments().get(documentSnapshots.size() - 1);
for (DocumentChange doc : documentSnapshots.getDocumentChanges()) {
if (doc.getType() == DocumentChange.Type.ADDED) {
//String postId = doc.getDocument().getId();
// contentSeen = doc.getDocument().toObject(ContentProfile.class);
// contentList.add(contentSeen);
contentProfileDashboard = doc.getDocument().toObject(ContentProfileDashboard.class);
contentListDashboard.add(contentProfileDashboard);
//adapterSeen.notifyDataSetChanged();
adapterProfileDashboard.notifyDataSetChanged();
}
}
}
}
});
}
}
any question?
Upvotes: 1