Trier la liste de discussion en fonction du message le plus récent avec Firebase

Nov 23 2020

Je ne sais pas pourquoi je suis resté coincé dans un problème selon lequel la liste de discussion ne trie pas par heure du dernier message ou par message le plus récent. J'ai essayé de stocker timestampdans la base de données et l' horodatage orderChildBy mais cela ne fonctionne toujours pas. ne fonctionne pas signifie que la liste n'est pas triée après chaque message et continue d'afficher la liste comme triée après le premier message.

Regardez l'image comment les chats sont désordonnés!

C'est ainsi que j'ai créé chatList firebaseDatabasedans ChatActiviy sur sendMessage:

    val timeAgo = Date().time

    val myTimeMap = HashMap<String, Any?>()
        myTimeMap["timestamp"] = timeAgo
        myTimeMap["id"] = friendId

    val friendTimeMap = HashMap<String, Any?>()
        friendTimeMap["timestamp"] = timeAgo
        friendTimeMap["id"] = currentUserID

    val chatListSenderReference = dbRef.child("ChatList").child(currentUserID).child(friendId)
        chatListSenderReference.keepSynced(true)
        chatListSenderReference.addListenerForSingleValueEvent(object : ValueEventListener{
              override fun onCancelled(p0: DatabaseError) {
              }
              override fun onDataChange(p0: DataSnapshot) {
                       if(!p0.exists()){
                             chatListSenderReference.updateChildren(friendTimeMap)
                       }
    val chatListReceiverReference = dbRef.child("ChatList").child(friendId).child(currentUserID)
        chatListReceiverReference.updateChildren(myTimeMap)
        }
    })

Lors de la récupération de la liste de discussion dans recyclerView, j'essaie d'obtenir les détails des utilisateurs pour chaque utilisateur qui est présenté comme l'enfant de currentUser dans la base de données. (Liste de discussion >> CurrentUserId)

ÉDITÉ

  private fun retrieveChatList() {

    usersChatList = ArrayList()
    val userRef = dbRef.child("ChatList").child(currentUserID).orderByChild("timestamp")
    userRef.addValueEventListener(object : ValueEventListener
    {
        override fun onCancelled(error: DatabaseError) {
        }

        override fun onDataChange(snapshot: DataSnapshot)
        {
            (usersChatList as ArrayList<String>).clear()
            if (snapshot.exists()){
                for (dataSnapshot in snapshot.children){
                    val userUid = dataSnapshot.key
                    if (userUid != null) {
                        (usersChatList as ArrayList<String>).add(userUid)
                    }
                }
                readChatList()
            }
        }
    })
}

private fun readChatList() {
    mUsers = ArrayList()
    val userRef = FirebaseFirestore.getInstance().collection("Users")
    userRef.get()
            .addOnSuccessListener { queryDocumentSnapshots ->
                mUsers?.clear()
                for (documentSnapshot in queryDocumentSnapshots) {
                    val user = documentSnapshot.toObject(User::class.java)
                    for (id in usersChatList!!){
                        if (user.getUid() == id){
                            (mUsers as ArrayList<User>).add(user)
                        }
                    }
                }
                retrieveGroupChatList()
                chatListAdapter?.notifyDataSetChanged()
                chatListAdapter = context?.let { ChatListAdapter(it, (mUsers as ArrayList<User>), true) }
                recyclerViewChatList.adapter = chatListAdapter

            }.addOnFailureListener { e ->
                Log.d(ContentValues.TAG, "UserAdapter-retrieveUsers: ", e)
            }

}

Et voici le chatListAdapter pour les informations sur les amis

private fun friendInfo(fullName: TextView, profileImage: CircleImageView, uid: String) {
        val userRef = FirebaseFirestore.getInstance().collection("Users").document(uid)
        userRef.get()
                .addOnSuccessListener {
                    if (it != null && it.exists()) {
                        val user = it.toObject(User::class.java)
                Picasso.get().load(user?.getImage()).placeholder(R.drawable.default_pro_pic).into(profileImage)
                fullName.text = user?.getFullName()
            }
        }
    }

Ceci est l'image de la base de données en temps réel et a une classe de modèle comme ChatList , chaque fois que j'envoie ou reçois un horodatage de message obtient une mise à jour.

et une autre image des utilisateurs dans le firestore et a une classe de modèle en tant qu'utilisateurs .

SOLUTION

J'ai une solution qui fonctionne, ici je crée ou mets à jour un champ en tant que lastMessageTimestamp dans la Firestorecollection Users afin que les utilisateurs puissent maintenant trier par lastMessageTimestamp .

   val timeAgo = Date().time
    
        val myFSMap = HashMap<String, Any?>()
            myFSMap["timestamp"] = timeAgo
    
        val friendFSMap = HashMap<String, Any?>()
            friendFSMap["timestamp"] = timeAgo
    
      //firebase chatlist references.
        val chatListSenderReference = dbRef.child("ChatList").child(currentUserID).child(friendId)
        val chatListReceiverReference = dbRef.child("ChatList").child(friendId).child(currentUserID)

      //Firestore Users references.
        val chatListSenderRef = fStore.collection("Users").document(currentUserID)
        val chatListReceiverRef = fStore.collection("Users").document(friendId)
    
        chatListSenderReference.addListenerForSingleValueEvent(object : ValueEventListener{
           override fun onDataChange(p0: DataSnapshot) {
                 if(!p0.exists()){
                    chatListSenderReference.setValue(friendId)
                    //update the timestamp in Users collection
                    chatListSenderRef.update(myFSMap)
                 }
                    chatListReceiverReference.setValue(currentUserID)
                    chatListReceiverRef.update(friendFSMap)

           override fun onCancelled(p0: DatabaseError) {
               }
            }
        })

Et au moment de la lecture, j'utilise orderBy pour les utilisateurs

 val userRef = FirebaseFirestore.getInstance().collection("Users").orderBy("lastMessageTimestamp" , Query.Direction.ASCENDING)

Mais ce n'est pas la solution complète car il semble que je lis et écris le lastMessageTimestamp à chaque fois sur la messagerie, ce qui peut augmenter le Firebase Billingmontant à d'énormes nombres effrayants. donc j'ai encore besoin d'une solution.

Réponses

ChuongLeVan Nov 26 2020 at 08:21

L'astuce simple est orderBy id du message. Parce que l'identifiant généré par Firebase est basé sur le temps réel + quelques facteurs. Essayons donc de classer par ID au lieu de votre horodatage. (note: juste l'identifiant généré par firebase)