DiffUtil.ItemCallback <T>被调用两次

时间:2019-11-29 17:07:28

标签: android android-recyclerview listadapter

我正在使用Firebase制作聊天应用程序,并且有一个文档监听器,因此每次收到新消息时,我都会将新列表设置为正在观察的LiveData<List<T>>的值我的片段,并向我的submistList()调用ListAdapter<>

我的问题是,每次添加新消息时,我都会在recyclerview上看到一个小的闪烁,并且在进一步调试之后,我发现DiffUtil.ItemCallback正在两次,尽管只调用了一次submitList()。 / p>

我真的不知道我错过了什么,谢谢您的帮助。

DiffUtil.ItemCallback

class ChatsDiffCallBack : DiffUtil.ItemCallback<Chat>() {
    override fun areItemsTheSame(oldItem: Chat, newItem: Chat): Boolean {
        Log.d("Adapter", "Old: ${oldItem.id} New: ${newItem.id}")
        Log.d("Adapter", "Equal: ${oldItem.id == newItem.id}")

        return oldItem.id == newItem.id
    }

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

适配器

class ChatAdapter : ListAdapter<Chat, ChatAdapter.ViewHolder>(ChatsDiffCallBack()) {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder.from(parent, viewType)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    override fun getItemViewType(position: Int): Int {
        if (getItem(position).chatType == ChatType.mine) return R.layout.my_chat_item
        return R.layout.their_chat_item
    }

    class ViewHolder private constructor(val binding: ViewDataBinding) :
        RecyclerView.ViewHolder(binding.root) {

        companion object {
            fun from(parent: ViewGroup, layoutId: Int): ViewHolder {
                val layoutInflater = LayoutInflater.from(parent.context)
                val binding: ViewDataBinding =
                    DataBindingUtil.inflate(layoutInflater, layoutId, parent, false)

                return ViewHolder(binding)
            }
        }

        fun bind(chat: Chat) {
            when (binding) {
                is MyChatItemBinding -> binding.chat = chat
                is TheirChatItemBinding -> binding.chat = chat
            }
            binding.executePendingBindings()
        }
    }
}

ViewModel

class ChatViewModel @Inject constructor(private val repository: ChatRepository) : BaseViewModel() {

    lateinit var userName: String

    val message = MutableLiveData<String>()

    private val _chats = MutableLiveData<List<Chat>>().apply { value = emptyList() }
    val chats: LiveData<List<Chat>> = _chats

    fun setup(userName: String?) {
        if (userName == null) return
        Log.d("Chat", "Username is: $userName")
        this.userName = userName
        getChats()
    }

    fun onSendClick() {
        if (userName.isEmpty() && message.value.toString().isEmpty()) return
        val chat = Chat(userName = userName, message = message.value.toString())

        repository.addMessage(chat).addOnSuccessListener {
            Log.d("Chat", "Added new message!")
        }.addOnFailureListener {
            Log.e("Chat", "Failed adding message")
        }
    }

    private fun getChats() {
        repository.getMessages().orderBy("timestamp", Query.Direction.ASCENDING)
            .addSnapshotListener { value, e ->

                if (value?.documents?.size == chats.value?.size) return@addSnapshotListener

                if (e != null) {
                    Log.e("Chat", "Listen Failed!", e)
                    return@addSnapshotListener
                }
                val tempChats = mutableListOf<Chat>()

                for (doc in value?.documents!!) {
                    val chat = Chat.fromDocumentSnapshot(doc)

                    chat.chatType = if (this.userName == chat.userName) ChatType.mine
                    else ChatType.theirs

                    tempChats.add(chat)
                }

                _chats.value = tempChats
            }
    }

}

片段

private fun initRecyclerView() {
    val adapter = ChatAdapter()
    binding.rv.adapter = adapter

    viewModel.chats.observe(viewLifecycleOwner, Observer {
        Log.d("ChatFragment", "*************")
        adapter.submitList(it.toList())
    })
}

1 个答案:

答案 0 :(得分:0)

我面临着同样的问题,DiffUtil.ItemCallback被调用了两次,而RecyclerView在删除项目时闪烁,要解决此问题,我不得不像这样重写getItemId。

 override fun getItemId(adapterPosition: Int): Long {
    return getItem(adapterPosition).getId()
}