【问题标题】:lateinit property binding has not been initializedlateinit 属性绑定尚未初始化
【发布时间】:2021-08-20 02:48:10
【问题描述】:

我知道有类似的问题,但是我就是找不到类似的东西,我一直在研究新的东西来学习,在将 kotlin 合成转换为viewvbinding 模式时,我遇到了这个错误

kotlin.UninitializedPropertyAccessException: lateinit property binding has not been initialized
        at com.codepalace.chatbot.ui.MessagingAdapter.onBindViewHolder(MessagingAdapter.kt:60)
        at com.codepalace.chatbot.ui.MessagingAdapter.onBindViewHolder(MessagingAdapter.kt:17)

它说我必须初始化绑定,但我不知道放在哪里。

这是代码。

class MessagingAdapter: RecyclerView.Adapter<MessagingAdapter.MessageViewHolder>() {

var messagesList = mutableListOf<Message>()
private lateinit var binding: MessageItemBinding


inner class MessageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    init {
        itemView.setOnClickListener {

            //Remove message on the item clicked
            messagesList.removeAt(adapterPosition)
            notifyItemRemoved(adapterPosition)
        }
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {

    return MessageViewHolder(
        LayoutInflater.from(parent.context).inflate(R.layout.message_item, parent, false)
    )
}

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

@SuppressLint("SetTextI18n")
override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
    val currentMessage = messagesList[position]


    when (currentMessage.id) {
        SEND_ID -> {
            holder.itemView.findViewById<View>(R.id.tv_message).apply {
                binding.tvMessage.text = currentMessage.message
                visibility = View.VISIBLE
            }
            holder.itemView.findViewById<View>(R.id.tv_bot_message).visibility = View.GONE
        }
        RECEIVE_ID -> {
            holder.itemView.findViewById<View>(R.id.tv_bot_message).apply {
                binding.tvBotMessage.text = currentMessage.message
                visibility = View.VISIBLE
            }
            holder.itemView.findViewById<View>(R.id.tv_message).visibility = View.GONE
        }
    }
}

fun insertMessage(message: Message) {
    this.messagesList.add(message)
    notifyItemInserted(messagesList.size)
}

【问题讨论】:

  • 为什么适配器类中有MessageItemBinding?我认为它应该放在ViewHolder 类中,所以在你的情况下是MessageViewHolder
  • 你能举个例子吗?
  • 我还是新手,所以我不太了解该放在哪里。
  • 好的,我可以尝试做一个简短的例子,并展示我如何制作 RecyclerView 适配器
  • 非常感谢,但是为了使用 xml 文件中的 id,我必须使用 MessageItemBinding,如果我尝试更改它,它也会出错

标签: android kotlin android-recyclerview data-binding


【解决方案1】:

private lateinit var binding: MessageItemBinding

你没有初始化binding对象,因为你把它定义为lateinit,那么你应该定义它。

这通常在onCreateViewHolder

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TrackedActivityHolder {
    val inflater = LayoutInflater.from(parent.context)
    binding = DataBindingUtil.inflate<MessageItemBinding>(inflater, R.layout.message_item, parent, false)
    return MessageViewHolder(
        binding
    )
}

更新

您需要在MessageViewHolder 构造函数中接受MessageItemBinding 类型而不是View,并使用itemView.root 获取列表项的根视图。

inner class MessageViewHolder(itemView: MessageItemBinding) : RecyclerView.ViewHolder(itemView.root) {
    init {
        itemView.root.setOnClickListener {

            //Remove message on the item clicked
            messagesList.removeAt(adapterPosition)
            notifyItemRemoved(adapterPosition)
        }
    }
}

【讨论】:

  • 嗨,我在 MessageItemBinding 上收到一个错误,表明参数不在其范围内
  • 嗨@JeffreyKurdtDreo,请查看答案中的更新部分
  • 仍有错误,参数不在其范围内。
  • setOnClickListener 也报错,提示未解析参考
  • 是否可以尝试编辑代码?我真的需要帮助
【解决方案2】:

您收到此错误的原因是 MessageItemBinding 不应该在 Adapter 中,而是在 ViewHolder 类中。你可以像这样制作 RecyclerView:

object MessageDiffCallback : DiffUtil.ItemCallback<Message>()
{
    override fun areItemsTheSame(
        oldItem: Message,
        newItem: Message
    ): Boolean =
            oldItem.id == newItem.id

    override fun areContentsTheSame(
        oldItem: Message,
        newItem: Message
    ): Boolean =
            oldItem == newItem
}

我假设Message 是一个数据类。你必须创建这个MessageDiffCallback 并以与我类似的方式覆盖这两个方法。

现在创建ViewHolder 类:

class MessageViewHolder private constructor(
    private val binding: MessageItemBinding
) : RecyclerView.ViewHolder(binding.root)
{
    companion object
    {
        fun create(parent: ViewGroup): MessageViewHolder 
        {
            val layoutInflater = LayoutInflater.from(parent.context)
            val binding = MessageItemBinding.inflate(layoutInflater, parent, false)
            return MessageViewHolder(
                binding
            )
        }
    }

    fun bind(
        message: Messaage
    )
    {
        // Here You can do everything. 
        // You pass the message and based on this You can set up a view and use binding
    }
}

现在是适配器类

class MessageAdapter : ListAdapter<Message, MessageViewHolder>(MessageDiffCallback)
{
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder =
            MessageViewHolder.create(parent)


    override fun onBindViewHolder(holder: MessageViewHolder, position: Int) =
            holder.bind(
                message = getItem(position),
            )
}

现在您应该有一个工作适配器。要将数据放入其中,请在您的片段/活动中使用 messageAdapter.submitList(messages)


也许不是最佳答案,因为它会更改您的代码并使用一些不同的逻辑,但它应该可以更好地工作。您可以查看google sample code here 或采取codelab here。注册后免费

【讨论】:

    猜你喜欢
    • 2021-10-13
    • 2017-03-03
    • 1970-01-01
    • 2020-12-31
    • 2021-06-11
    • 2017-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多