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