Повторяется просмотр в ресайкл

#android #firebase #kotlin #firebase-realtime-database

#Android #firebase #kotlin #firebase-база данных в реальном времени

Вопрос:

Я создаю приложение для чата с использованием Kotlin и firebase и запускаю приведенные ниже функции для создания списка чатов во внешнем интерфейсе. Он отлично работает при загрузке. Но в ту секунду, когда пользователь отправляет сообщение, он повторяет вывод столько же раз, сколько элементов, уже находящихся в массиве mUsers? Есть мысли о том, что я здесь делаю не так?

Вывод приведенного ниже кода

     override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    // Inflate the layout for this fragment
    val view = inflater.inflate(R.layout.fragment_messages, container, false)

    recycler_view_msgList = view.findViewById(R.id.recycler_view_msglist)
    recycler_view_msgList.setHasFixedSize(true)
    recycler_view_msgList.layoutManager = LinearLayoutManager(context)

    firebaseUser = FirebaseAuth.getInstance().currentUser

    usersMsgList = ArrayList()

    val ref = FirebaseDatabase.getInstance().reference.child("ChatList").child(firebaseUser!!.uid).orderByChild(
        "chattimeStmp"
    )
    ref.addValueEventListener(object : ValueEventListener {

        override fun onDataChange(p0: DataSnapshot) {
            (usersMsgList as ArrayList).clear()
            for (dataSnapshot in p0.children) {
                val messageList = dataSnapshot.getValue(MessageList::class.java)
                (usersMsgList as ArrayList).add(messageList!!)
            }
            (usersMsgList as ArrayList<MessageList>).reverse()
            retrieveMessageList()
        }

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

    updateToken(FirebaseInstanceId.getInstance().token)
    return view
}

private fun retrieveMessageList() {
    mUsers = ArrayList()
    (mUsers as ArrayList).clear()
    val arraysize = usersMsgList!!.size
    val i = 0
    for (eachMessageList in usersMsgList!!) {
        if (eachMessageList.getId() != null) {
            val receiverId = eachMessageList.getId()
            if (receiverId != null) {
                val ref =
                    FirebaseDatabase.getInstance().reference.child("Users").orderByChild("uid").equalTo(receiverId)
                ref.addListenerForSingleValueEvent(object : ValueEventListener {

                    override fun onDataChange(p0: DataSnapshot) {
                        for (dataSnapshot in p0.children) {
                            val user = dataSnapshot.getValue(Users::class.java)
                            if (user != null) {
                                (mUsers as ArrayList).add(user)
                            }
                        }
                        userMsgAdapter = UserMsgAdapter(context!!, mUsers as ArrayList<Users>,true)
                        userMsgAdapter!!.notifyDataSetChanged()
                        recycler_view_msgList.adapter = userMsgAdapter
                    }

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

Ответ №1:

Насколько я могу судить, вы получаете сообщения несколько раз. На самом деле, ваш код может быть намного проще:

 override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? {

    // Inflate the layout for this fragment
    val view = inflater.inflate(R.layout.fragment_messages, container, false)

    recycler_view_msgList = view.findViewById(R.id.recycler_view_msglist)
    recycler_view_msgList.setHasFixedSize(true)
    recycler_view_msgList.layoutManager = LinearLayoutManager(context)

    firebaseUser = FirebaseAuth.getInstance().currentUser

    usersMsgList = ArrayList()
    userMsgAdapter = UserMsgAdapter(context!!, mUsers as ArrayList<Users>,true)
    recycler_view_msgList.adapter = userMsgAdapter

    val ref = FirebaseDatabase.getInstance().reference.child("ChatList").child(firebaseUser!!.uid).orderByChild(
        "chattimeStmp"
    )
    ref.addValueEventListener(object : ValueEventListener {
        override fun onDataChange(p0: DataSnapshot) {
            (usersMsgList as ArrayList).clear()
            for (dataSnapshot in p0.children) {
                val messageList = dataSnapshot.getValue(MessageList::class.java)
                (usersMsgList as ArrayList).add(messageList!!)
            }
            (usersMsgList as ArrayList<MessageList>).reverse()
            userMsgAdapter!!.notifyDataSetChanged()
        }

        override fun onCancelled(error: DatabaseError) {
            throw error.toException() // never ignore errors
        }
    })

    updateToken(FirebaseInstanceId.getInstance().token)
    return view
}
  

retrieveMessageList Из того, что я вижу, с помощью приведенного выше кода вы можете полностью удалить. Вы просто создаете адаптер и регистрируете прослушиватель для сообщений один раз, onCreateView а затем сообщаете адаптеру, когда данные были изменены.

Комментарии:

1. Привет, Фрэнк, спасибо, что посмотрели на это, я использую retrieveMessageList, чтобы получить подробную информацию о каждом пользователе, присутствующем в userMsgList. Если я не запускаю retrieveMessageList, mUsers пуст, а ChatList будет пустым…

2. Ах, извините, я это пропустил. Но в представлении отображается список сообщений, верно? В любом случае: вы должны подключить адаптер, onCreateView как я сделал здесь, и далее onDataChange , поскольку он вызывается повторно. Обычно вам требуется только один экземпляр адаптера на весь срок службы представления,.

3. ах, да, представление сбивает с толку, пришлось замаскировать, извините, это список чатов, у меня запущено два адаптера — один для получения списка чатов, которые есть у пользователя, и два, чтобы заставить пользовательские объекты заполнять представление списка чатов на интерфейсе. Проблема, на мой взгляд, заключается в том, что я пытаюсь выполнить цикл запроса, запрашивая конкретного пользователя, а не загружая весь узел Users, а затем заполняя mUsers, является ли мой подход неправильным? — внешний цикл находится в массиве объектов userMsgList…

4. В общем, это антипаттерн: FirebaseDatabase.getInstance().reference.child("Users").orderByChild("uid").equalTo(receiverId) . При хранении профилей пользователей рекомендуется использовать их UID в качестве ключа. При этом приведенный выше код становится: FirebaseDatabase.getInstance().reference.child("Users").child(receiverId) и вам больше не нужен цикл onDataChange (поскольку вы уже читаете один конкретный узел).

5. антипаттерн — о, хорошо, тогда я отойду от этого подхода, буду делать это шаг за шагом, спасибо, Фрэнк, ура