【问题标题】:Can't show all messages from Firebase Database via RecyclerView无法通过 RecyclerView 显示来自 Firebase 数据库的所有消息
【发布时间】:2021-03-02 09:21:44
【问题描述】:

在聊天应用程序中,我使用 Firebase 数据库来存储用户消息、片段、ViewModel 和 RecyclerView,而我的麻烦是,当您重新加载应用程序时,它会通过 RecyclerView 显示最后一个用户的消息,因此当您开始对话时它工作正常,您可以发送和检索消息,但是当重新加载应用程序时,两个用户在开始对话时只会看到最后一条消息(每个用户一个)。我需要显示所有消息,但不知道如何解决我的问题。所有文件:

ChatViewModel.kt

class ChatViewModel: ViewModel() {

    private val _messageFrom = MutableLiveData<ChatMessage>()
    val messageFrom: LiveData<ChatMessage>
        get() = _messageFrom

    private val _messageTo = MutableLiveData<ChatMessage>()
    val messageTo: LiveData<ChatMessage>
        get() = _messageTo

    init {
        listenForMessages()
    }

     fun sendMessage(message: String, toId: String) {
         val reference = FirebaseDatabase.getInstance().getReference("/messages").push()
         val fromId = FirebaseAuth.getInstance().uid
         val chatMessage = ChatMessage(reference.key!!, message, fromId!!, toId, System.currentTimeMillis() / 1000)
         reference.setValue(chatMessage)
                 .addOnSuccessListener {
                     Log.d("ChatViewModel", "Send your message: ${reference.key}")
                 }
     }

   private fun listenForMessages() {
        val reference = FirebaseDatabase.getInstance().getReference("/messages")

        reference.addChildEventListener(object: ChildEventListener {
            override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
                val chatMessage = snapshot.getValue(ChatMessage::class.java)
                snapshot.children.forEach {
                    if (chatMessage != null) {
                        if (chatMessage.fromId == FirebaseAuth.getInstance().uid ) {
                            Log.d("ChatViewModel", "From: ${chatMessage.text}")
                            _messageFrom.postValue(chatMessage)
                        } else {
                            "To: ${chatMessage.text}"
                            _messageTo.postValue(chatMessage)
                        }
                    }
                }
            }

            override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
                TODO("Not yet implemented")
            }

            override fun onChildRemoved(snapshot: DataSnapshot) {
                TODO("Not yet implemented")
            }

            override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
                TODO("Not yet implemented")
            }

            override fun onCancelled(error: DatabaseError) {
                TODO("Not yet implemented")
            }

        })
    }

}

ChatRecyclerViewAdapter.kt

private const val VIEW_TYPE_TO_MESSAGE = 1
private const val VIEW_TYPE_FROM_MESSAGE = 2

class ChatRecyclerFromAdapter: RecyclerView.Adapter<ChatRecyclerFromAdapter.ViewHolder>() {
    private var list: ArrayList<ChatMessage> = ArrayList()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return if(viewType == VIEW_TYPE_FROM_MESSAGE) {
            FromMessageViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.chat_recycler_view_item_from, parent, false))
        } else {
            ToMessagesViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.chat_recycler_view_item_to, parent, false))
        }
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            val message = list[position]
        holder.bind(message)
    }

    override fun getItemViewType(position: Int): Int {
        val message = list[position]

        return if (message.fromId == FirebaseAuth.getInstance().uid) {
            VIEW_TYPE_TO_MESSAGE
        } else {
            VIEW_TYPE_FROM_MESSAGE
        }
    }

    fun getMessages(chatMessage: ArrayList<ChatMessage>){
        list = chatMessage
        notifyDataSetChanged()
    }

    fun setMessages(chatMessage: ChatMessage) {
        list.add(chatMessage)
        notifyDataSetChanged()
    }

    override fun getItemCount(): Int {
        return list.size
    }

   inner class FromMessageViewHolder (itemView: View): ViewHolder(itemView) {
        private val messageText = itemView.findViewById<TextView>(R.id.message_text_view_chat)

       override fun bind(chatMessage: ChatMessage) {
           messageText.text = chatMessage.text
       }
    }

    inner class ToMessagesViewHolder(itemView: View): ViewHolder(itemView) {
        private val messageText = itemView.findViewById<TextView>(R.id.message_text_view_chat_to)
        override fun bind(chatMessage: ChatMessage) {
            messageText.text = chatMessage.text
        }
    }



   open class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
       open fun bind (chatMessage: ChatMessage) {

        }
    }


}

ChatFragment.kt

class ChatFragment: Fragment() {
    private val chatViewModel by lazy { ViewModelProvider(this).get(ChatViewModel::class.java) }

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

        val binding = ChatFragmentBinding.inflate(inflater)
        val user = ChatFragmentArgs.fromBundle(requireArguments()).selectedUser
        (activity as AppCompatActivity).supportActionBar?.title = user.username
        val messageTextEdit = binding.sendEditText.text

        binding.sendButton.setOnClickListener {
            chatViewModel.sendMessage(messageTextEdit.toString(), user.uid)
        }
        return binding.root
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        val adapter = ChatRecyclerFromAdapter()
        chat_recycler_view.layoutManager = LinearLayoutManager(requireContext())
        chat_recycler_view.adapter = adapter

        chatViewModel.messageFrom.observe(viewLifecycleOwner, {
           adapter.setMessages(it)
        })

        chatViewModel.messageTo.observe(viewLifecycleOwner, {
            adapter.setMessages(it)
        })
    }
}

【问题讨论】:

    标签: android firebase kotlin firebase-realtime-database android-recyclerview


    【解决方案1】:

    ViewModelAdapter 存在问题 当应用程序启动时,我只添加了最后一条消息,因为它只有最后一条消息,所以解决方案是使用数组 这里 ChatViewModel.kt 函数已更新:

     private fun listenForMessages() {
            val reference = FirebaseDatabase.getInstance().getReference("/messages")
            val allMessages = arrayListOf<ChatMessage>()
            reference.addChildEventListener(object: ChildEventListener {
                override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
                    val chatMessage = snapshot.getValue(ChatMessage::class.java)
                        if (chatMessage != null) {
                            if (chatMessage.fromId == FirebaseAuth.getInstance().uid ) {
                                Log.d("ChatViewModel", "From: ${chatMessage.text}")
                               allMessages.add(chatMessage)
                            } else if (chatMessage.toId == FirebaseAuth.getInstance().uid) {
                                "To: ${chatMessage.text}"
                                allMessages.add(chatMessage)
                            }
                            _messages.postValue(allMessages)
                        }
                }
    

    而在adapter中我们只需要删除setMessages()并在Fragment中使用getMessages(),像这样:

     override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)
    
            val adapter = ChatRecyclerFromAdapter()
            chat_recycler_view.layoutManager = LinearLayoutManager(requireContext())
            chat_recycler_view.adapter = adapter
    
            chatViewModel.messages.observe(viewLifecycleOwner, {
               adapter.getMessages(it)
            })
    
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-08-30
      • 2019-05-24
      • 2020-06-25
      • 2017-11-20
      • 1970-01-01
      • 1970-01-01
      • 2021-08-28
      相关资源
      最近更新 更多