Как эффективно хранить или извлекать сообщения в приложении Firestore Chat без этой проблемы? - PullRequest
3 голосов
/ 05 января 2020

Моя проблема заключается в том, что вместо добавления новых данных существующие данные в базе данных Firestore обновляются. Это приводит к отображению последнего сообщения, отправленного или полученного в ChatActivity. Кроме того, сообщение, которое я отправляю, появляется дважды на экране после отправки, но как только я покидаю действие и снова открываю его, как я только что сказал, отображается только последнее сообщение, которое было отправлено или получено в ChatActivity. После долгих поисков в inte rnet и самостоятельного тестирования различных альтернатив, но я не смог решить эту проблему, и теперь я обращаюсь к этому сообществу за помощью.

Я разместил ниже методы, которыми я являюсь использование для отправки моего сообщения из приложения в базу данных и способ отображения этих сообщений.

метод отправки сообщения

private void sendMessage(String sender,String receiver,String message){
        DocumentReference documentReference = rootRef.collection("chats").document(roomId).collection("messages").document(roomId);
        Map<String,Object> user = new HashMap<>();
        user.put("sender",sender);
        user.put("receiver",receiver);
        user.put("message",message);
        user.put("time", FieldValue.serverTimestamp());
        user.put("rid",roomId);
        documentReference.set(user,SetOptions.merge()).addOnSuccessListener(new OnSuccessListener<Void>() {
            @Override
            public void onSuccess(Void aVoid) {
                Log.d(TAG, "onSuccess: MessageSent "+ userId);
            }
        }).addOnFailureListener(new OnFailureListener() {
            @Override
            public void onFailure(@NonNull Exception e) {
                Log.d(TAG, "onSuccess: Error"+ userId);
            }
        });
    }

метод получения сообщения

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);
    collectionReference.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;
            }
            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);
                }
            }
        }
    });
}

Ответы [ 2 ]

1 голос
/ 05 января 2020

Я думаю, что новые сообщения переопределяют старые сообщения из-за этой строки:

DocumentReference documentReference = rootRef.collection("chats").document(roomId).collection("messages").document(roomId);

Я считаю, что вам нужно, чтобы в последнем вызове .document () было что-то отличное от roomId для значения, потому что если roomId остается прежним, и вы никогда не сможете иметь более одного сообщения в одной коллекции сообщений. Возможно, измените roomId на messageId.

Информацию о проблеме чтения смотрите в ответе @Frank van Puffelen

0 голосов
/ 05 января 2020

Поскольку вы подключаете слушателя с помощью addSnapshotListener, ваш метод onEvent будет вызываться один раз, когда вы присоединяете слушателя, а затем каждый раз, когда данные, которые он слушает, модифицируются. Поэтому при добавлении сообщения ваш onEvent снова вызывается.

Каждый раз, когда запускается onEvent, вы читаете все сообщения из базы данных и добавляете их в свой просмотр. Так что в первый раз это правильно, так как вы добавляете все исходные сообщения. Но при последующих вызовах вы повторно добавляете те же сообщения, которые уже обрабатывали снова и снова.

У вас есть два основных варианта решения этой проблемы:

  1. Стирание существующих сообщения перед обработкой
  2. Обрабатывать только обновления

Удаление существующих сообщений самое простое, поскольку все, что вам нужно сделать, это очистить `` в начале 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);
                }
            }
        }
    });
}

. Для более полного решения вам понадобится:

  1. Обрабатывайте также события MODIFIED и REMOVED, обновляя и удаляя существующие сообщения в / из mchat.
  2. , только один раз звоните new MessageAdapter(MessageActivity.this,mchat), а при последующих обновлениях звоните adapter.notifyDataSetChanged, чтобы сообщить это из изменений.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...