Raymond Gitonga
Raymond Gitonga

Reputation: 171

lateinit property listener has not been initialized

I am trying to add an onclick listener to a recyclerview item i however keep getting an error that states the listener has not been initialised, but it has been initialised, what am i doing wrong.

Note: The recycler view is a nested recyclerview, and am adding the onclick to the child recyclerview

Here is how my adapter looks like

class ProductAdapter(private val productModel: List<Product>): RecyclerView.Adapter<ProductAdapter.ProductView>(){

    private lateinit var listener: OnItemClickListener

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductView {
        val view = LayoutInflater.from(parent.context).inflate(R.layout.product_item, parent, false)
        return ProductView(view, productModel, listener)
    }

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

    override fun onBindViewHolder(holder: ProductView, position: Int) {
        var product = productModel[position]
        //
        holder.product = listOf(product)

    }

    class ProductView(itemView: View, var product: List<Product>, listener: OnItemClickListener) : RecyclerView.ViewHolder(itemView){
        //

        init {
            itemView.setOnClickListener {
                listener.onButtonClick(product[0])
            }
        }

    }

    interface OnItemClickListener{
        fun onButtonClick(productModel: Product)
    }

    fun setOnItemClickListener(listener: OnItemClickListener){
        this.listener = listener
    }

}

And this is how am implementing it in my fragment

private fun addToCart(){
        productAdapter?.setOnItemClickListener(object : ProductAdapter.OnItemClickListener {
            override fun onButtonClick(productModel: Product) {
                Log.v("Clicked", ""+productModel.productName)

            }

        })
    }

UPDATE: I made the listener nullable i am no longer getting the error but the click doesn't log anything

private var listener: OnItemClickListener? = null

Upvotes: 0

Views: 7465

Answers (3)

Eslam Ahmad
Eslam Ahmad

Reputation: 589

Main issue here is you pass listener to ProductView in constructor and use it in init block, which called from onCreateViewHolder before you set your listener

So to solve this issue you have two options

1- Make listener nullable and set it when u need, something like

private var listener: OnItemClickListener?

Then when you use it

class ProductView(itemView: View, var product: List<Product>, listener: OnItemClickListener?) : RecyclerView.ViewHolder(itemView){
        val foodImg: ImageView = itemView.findViewById(R.id.foodImg)
        val foodName: TextView = itemView.findViewById(R.id.foodName)
        val foodDesc: TextView = itemView.findViewById(R.id.foodDesc)
        val foodPrice: TextView = itemView.findViewById(R.id.foodPrice)
        private val addToCart: ImageView = itemView.findViewById(R.id.addToCart)
        private lateinit var repository: MainRepository


        init {
            itemView.setOnClickListener {
                listener?.onButtonClick(product[0])
            }
        }

    }

2- Pass OnItemClickListener in adapter constructor

class ProductAdapter(private val productModel: List<Product>, private val listener: OnItemClickListener): RecyclerView.Adapter<ProductAdapter.ProductView>(){
 private lateinit var listener: OnItemClickListener //remove this listener
.....

}

and you can init your adapter like this

val adapter = ProductAdapter(productModel, object : ProductAdapter.OnItemClickListener {
            override fun onButtonClick(productModel: Product) {
                Log.v("Clicked", ""+productModel.productName)

            }

        })

Actually i prefer second option.

Upvotes: 0

Natig Babayev
Natig Babayev

Reputation: 3305

Instead of using setOnItemClickListener(), you can set listener on while constructing adapter. This will ensure that you always set click listener for adapter:

class ProductAdapter(private val productModel: List<Product>, listener: OnItemClickListener): RecyclerView.Adapter<ProductAdapter.ProductView>(){
    // ...
}

Another option is making private lateinit var listener: OnItemClickListener nullable. However, it's not good practice if listener is mandatory to set:

class ProductAdapter(private val productModel: List<Product>): RecyclerView.Adapter<ProductAdapter.ProductView>(){

    private var listener: OnItemClickListener? = null
    // ...
}

Upvotes: 0

CommonsWare
CommonsWare

Reputation: 1007399

private lateinit var listener: OnItemClickListener

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductView {
    val view = LayoutInflater.from(parent.context).inflate(R.layout.product_item, parent, false)
    return ProductView(view, productModel, listener)
}

You need to initialize listener before you use it. You are using it in onCreateViewHolder(). Make sure that you initialize listener before attaching your ProductAdapter to a RecyclerView.

Upvotes: 0

Related Questions