【问题标题】:DiffUtil.ItemCallback<T> is called twiceDiffUtil.ItemCallback<T> 被调用两次
【发布时间】:2019-11-29 17:07:28
【问题描述】:

我正在使用 Firebase 制作一个聊天应用程序,并且我为我的文档设置了一个侦听器,因此每次有新消息时,我都会将新列表设置为我在 Fragment 中观察到的 LiveData&lt;List&lt;T&gt;&gt; 的值并致电submistList() 到我的ListAdapter&lt;&gt;

我的问题是每次我添加一条新消息时,我都会在 recyclerview 上看到一个小闪烁,经过进一步调试,我发现我的 DiffUtil.ItemCallback 是两次,尽管我只调用了一次 submitList()

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

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()
        }
    }
}

视图模型

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())
    })
}

【问题讨论】:

    标签: android android-recyclerview listadapter


    【解决方案1】:

    我遇到了同样的问题,DiffUtil.ItemCallback 被调用了两次,并且 RecyclerView 在删除项目时闪烁,要解决这个问题,我必须像这样覆盖 getItemId。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-01
      • 2012-05-05
      • 2017-01-19
      • 2014-02-04
      • 2016-12-13
      • 2016-01-30
      • 2015-12-20
      • 2019-04-04
      相关资源
      最近更新 更多