I know that there are similar questions to this, but I just cant find something that is similar, I've been studying new things to learn, and while converting kotlin synthetics to viewvbinding
mode, I've encountered this error
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)
It says that I have to initialize the binding, but I dont know where to put it.
This is the code.
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)
}
private lateinit var binding: MessageItemBinding
You didn't initialize the binding
object, as you defined it as lateinit, then you should define it.
This is typically in 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
)
}
UPDATE
You need to accept MessageItemBinding
type instead of View
in the MessageViewHolder
constructor, and use itemView.root
to get the root view of the list item.
inner class MessageViewHolder(itemView: MessageItemBinding) : RecyclerView.ViewHolder(itemView.root) {
init {
itemView.root.setOnClickListener {
//Remove message on the item clicked
messagesList.removeAt(adapterPosition)
notifyItemRemoved(adapterPosition)
}
}
}
The reason why You get this error is that MessageItemBinding
should not be in Adapter but in ViewHolder class. You can make RecyclerView like this:
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
}
I assume that Message
is a data class. You have to create this MessageDiffCallback
and override these 2 methods in a similar way that I did it.
Now Create ViewHolder
class:
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
}
}
And now Adapter class
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),
)
}
Now You should have a working adapter. To put data in it use messageAdapter.submitList(messages)
in Your Fragment/Activity
Maybe not the best answer because it changes Your code and uses a little different logic but it should work better. You can check google sample code here or take codelab here . It is free after signing up
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.