Поскольку вы подключаете слушателя с помощью addSnapshotListener
, ваш метод onEvent
будет вызываться один раз, когда вы присоединяете слушателя, а затем каждый раз, когда данные, которые он слушает, модифицируются. Поэтому при добавлении сообщения ваш onEvent
снова вызывается.
Каждый раз, когда запускается onEvent
, вы читаете все сообщения из базы данных и добавляете их в свой просмотр. Так что в первый раз это правильно, так как вы добавляете все исходные сообщения. Но при последующих вызовах вы повторно добавляете те же сообщения, которые уже обрабатывали снова и снова.
У вас есть два основных варианта решения этой проблемы:
- Стирание существующих сообщения перед обработкой
- Обрабатывать только обновления
Удаление существующих сообщений самое простое, поскольку все, что вам нужно сделать, это очистить `` в начале onEvent
:
private void readMessages(final String userId, final String recipientId){
mchat = new ArrayList<>();
CollectionReference collectionReference = rootRef.collection("chats").document(roomId).collection("messages");
collectionReference.orderBy("time", Query.Direction.DESCENDING).addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(@Nullable QuerySnapshot documentSnapshots, @Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.e(TAG, "onEvent: Listen failed.", e);
return;
}
mChat.clear();
if(documentSnapshots!=null){
for(QueryDocumentSnapshot queryDocumentSnapshots : documentSnapshots){
Chat chat = queryDocumentSnapshots.toObject(Chat.class);
if(chat.getReceiver().equals(recipientId)&&chat.getSender().equals(userId)||
chat.getReceiver().equals(userId)&&chat.getSender().equals(recipientId)){
mchat.add(chat);
}
messageAdapter = new MessageAdapter(MessageActivity.this,mchat);
recyclerView.setAdapter(messageAdapter);
}
}
}
});
}
Обратите внимание, что я также изменил место вызова .orderBy("time", Query.Direction.DESCENDING)
. Каждый вызов orderBy
(и большинства других методов построения запросов) возвращает новый объект, поэтому вам нужно объединить вызовы в цепочку.
Обработка только обновлений немного сложнее , но будет более эффективным. Это означает, что когда у вас много документов, у вас меньше шансов мерцать в вашем пользовательском интерфейсе.
Я настоятельно рекомендую прочитать обработку изменений между снимками в документации. В самом простом случае, когда вы добавляете в собрание только новые документы, вы можете получить:
private void readMessages(final String userId, final String recipientId){
mchat = new ArrayList<>();
CollectionReference collectionReference = rootRef.collection("chats").document(roomId).collection("messages");
collectionReference.orderBy("time", Query.Direction.DESCENDING).addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(@Nullable QuerySnapshot documentSnapshots, @Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.e(TAG, "onEvent: Listen failed.", e);
return;
}
mChat.clear();
if(documentSnapshots!=null){
for(QueryDocumentSnapshot queryDocumentSnapshots : documentSnapshots.getDocumentChanges()){ // first change is here
switch (dc.getType()) {
case ADDED:
Chat chat = queryDocumentSnapshots.toObject(Chat.class);
if(chat.getReceiver().equals(recipientId)&&chat.getSender().equals(userId)||
chat.getReceiver().equals(userId)&&chat.getSender().equals(recipientId)){
mchat.add(chat);
}
break;
case MODIFIED:
Log.d(TAG, "Modified city: " + dc.getDocument().getData());
break;
case REMOVED:
Log.d(TAG, "Removed city: " + dc.getDocument().getData());
break;
}
messageAdapter = new MessageAdapter(MessageActivity.this,mchat);
recyclerView.setAdapter(messageAdapter);
}
}
}
});
}
. Для более полного решения вам понадобится:
- Обрабатывайте также события
MODIFIED
и REMOVED
, обновляя и удаляя существующие сообщения в / из mchat
. - , только один раз звоните
new MessageAdapter(MessageActivity.this,mchat)
, а при последующих обновлениях звоните adapter.notifyDataSetChanged
, чтобы сообщить это из изменений.