Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/178.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 滚动时在“回收器”视图中使用多个视图保持器复制项目_Android_Firebase_Firebase Realtime Database_Android Recyclerview_Android Viewholder - Fatal编程技术网

Android 滚动时在“回收器”视图中使用多个视图保持器复制项目

Android 滚动时在“回收器”视图中使用多个视图保持器复制项目,android,firebase,firebase-realtime-database,android-recyclerview,android-viewholder,Android,Firebase,Firebase Realtime Database,Android Recyclerview,Android Viewholder,我正在构建一个聊天应用程序,它必须在RecyclerView中膨胀两个视图(每个视图用于发送的消息和接收的消息)首次加载RecyclerView时,视图被正确加载,但当我滚动时,视图被复制,有些甚至被删除。 我发现这个问题的原因与回收者视图如何回收其视图有关。因为如果我设置了holder.setIsRecyclable(false),这不会发生。 但我不想这样做,因为它违背了RecyclerView的目的,而且滚动也变得滞后 以下是我的适配器代码: class MessageAdapter( v

我正在构建一个聊天应用程序,它必须在RecyclerView中膨胀两个视图(每个视图用于发送的消息和接收的消息)首次加载RecyclerView时,视图被正确加载,但当我滚动时,视图被复制,有些甚至被删除。

我发现这个问题的原因与回收者视图如何回收其视图有关。因为如果我设置了holder.setIsRecyclable(false),这不会发生。 但我不想这样做,因为它违背了RecyclerView的目的,而且滚动也变得滞后

以下是我的适配器代码:

class MessageAdapter(
val db: FirebaseDatabase,
val auth: FirebaseAuth,
private val receiverUserID: String
) :
androidx.recyclerview.widget.ListAdapter<Chat, RecyclerView.ViewHolder>(
    DIFF_UTIL
) {

companion object {
    const val RIGHT_SIDE_VIEW_HOLDER = 0
    const val LEFT_SIDE_VIEW_HOLDER = 1

    val DIFF_UTIL = object : DiffUtil.ItemCallback<Chat>() {
        override fun areItemsTheSame(oldItem: Chat, newItem: Chat): Boolean {
            return oldItem.messageID == newItem.messageID
        }

        override fun areContentsTheSame(oldItem: Chat, newItem: Chat): Boolean {
            return oldItem == newItem
        }

    }
}



**override fun getItemViewType(position: Int): Int {
    
    return if (currentList[position].senderID == auth.currentUser!!.uid) {

        RIGHT_SIDE_VIEW_HOLDER //load if we sent that message
    } else {
       
        LEFT_SIDE_VIEW_HOLDER //load if we received that message
    }
}**


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
   
    return if (viewType == RIGHT_SIDE_VIEW_HOLDER) {
        //for loading the sent message(right hand side view)
        val binding = AdapterRightMessageHolderBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        RightMessageViewHolder(binding)
    } else {   //for loading the received message(left hand side view)
        val binding = AdapterLeftMessageHolderBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        LeftMessageViewHolder(binding)
    }
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {

    when (holder.itemViewType) {

        //for the messages that we send
        RIGHT_SIDE_VIEW_HOLDER -> {
            (holder as RightMessageViewHolder).apply {

                //for image messages
                if (getItem(position).textMessage == IMAGE_MESSAGE && getItem(position).imageUrl.isNotEmpty()) {
                    Glide.with(this.binding.root).load(getItem(position).imageUrl)
                        .into(this.binding.rightImageView)
                    this.binding.rightMessageCardView.visibility = GONE
                } else {
                    //for text message
                    this.binding.rightMessageTextView.text = getItem(position).textMessage
                    this.binding.rightImageCardView.visibility = GONE
                }

                //for SEEN message//we show if our message was the last message
                if (getItem(position) == currentList.last()) {
                    this.binding.rightSeenTextView.isVisible = true
                
                    if (getItem(position).seen) {
                        this.binding.rightSeenTextView.text = "Seen"
                    } else {
                       this.binding.rightSeenTextView.text = "Sent"
                    }

               } else {
                    this.binding.rightSeenTextView.visibility = GONE
                }
            }


        }

        //for the messages that we receive
        LEFT_SIDE_VIEW_HOLDER -> {
            (holder as LeftMessageViewHolder).apply {

                //for loading the profile pic
                db.getReference(USERS).child(receiverUserID)
                    .addListenerForSingleValueEvent(object : ValueEventListener {
                        override fun onDataChange(snapshot: DataSnapshot) {
                            val user = snapshot.getValue(User::class.java)
                            Glide.with(binding.root).load(user?.profilePic)
                                .into(binding.leftReceiverProfilePic)
                        }

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

                    })

                //we don't load the profile pic of the person on the left if they send a CONSECUTIVE MESSAGE
                if (holder.adapterPosition > 0) {
                    if (getItem(position).senderID == getItem(position - 1).senderID) {
                        this.binding.leftReceiverProfilePic.visibility = INVISIBLE
                    } else {
                        this.binding.leftReceiverProfilePic.visibility = VISIBLE
                    }
                }

                //for image messages
                if (getItem(position).textMessage == IMAGE_MESSAGE && getItem(position).imageUrl.isNotEmpty()) {

                    Glide.with(this.binding.root).load(getItem(position).imageUrl)
                        .into(this.binding.leftImageView)
                    this.binding.leftMessageCardView.visibility = GONE

                } else {
                    //for text message
                    this.binding.leftMessageTextView.text = getItem(position).textMessage
                    this.binding.leftImageCardView.visibility = GONE

                }


            }

        }
    }
}


//view holder for inflating the view of the messages that we RECEIVE
inner class LeftMessageViewHolder(val binding: AdapterLeftMessageHolderBinding) :
    RecyclerView.ViewHolder(binding.root) {


}

//view holder for inflating the view of the messages that we SEND
inner class RightMessageViewHolder(val binding: AdapterRightMessageHolderBinding) :
    RecyclerView.ViewHolder(binding.root) {


}}
我做了一些测试,发现这些不是原因:

  • 具有多个视图持有者的。当我使用单个ViewHolder时也会发生同样的情况

  • onBindViewHolder()中的视图设置为可见/不可见/消失。我将所有视图都设置为可见,但它仍然发生


  • 我100%确信这个问题与RecyclerView如何回收其视图有关,但我不知道如何根据这一点更正我的代码。感谢您的帮助

    你是怎么解决的?你是怎么解决的?
    messageRecyclerView.apply {
            
            val linearLayoutManager = LinearLayoutManager(context)
            
            //linearLayoutManager.stackFromEnd = true
    
            this.layoutManager = linearLayoutManager
    
            this.adapter = messageAdapter
    
        }
    
    db.getReference(CHATS).child(chatUID).addValueEventListener(object : ValueEventListener {
            override fun onDataChange(snapshot: DataSnapshot) {
                Log.d(TAG, "onDataChange: Messages being loaded")
                if (snapshot.exists()) {
                    chatList.clear()
                    for (child in snapshot.children) {
                        val message = child.getValue(Chat::class.java)
                        chatList.add(message!!)
    
                        //submit the list
                        messageAdapter.submitList(chatList.toList())
                    }
    
    
                }
    
    
    
            }
    
            override fun onCancelled(error: DatabaseError) {
                TODO("Not yet implemented")
            }
    
        })