Reputation: 171
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
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
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
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