Search code examples
androidkotlinandroid-recyclerviewonitemclicklistener

Implementing click listener for RecyclerView adapter correctly


What's the correct way to create a click listener for an item in a RecyclerView adapter? This tutorial says it should be done in onBindViewHolder but others have said in onCreateViewHolder and I've not seen any tutorials for the latter hence I'm perplexed.

class MyRVAdapter(private val myList: ArrayList<Item>) : RecyclerView.Adapter<MyRVAdapter.ViewHolder>() {
    override fun getItemCount(): Int {
        return myList.size
    }

    class ViewHolder (itemView : View):RecyclerView.ViewHolder(itemView) {
        // val myButton = itemView.findViewById<Button>(R.id.btn_A)!!
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.myButton.text = (myList[position].btnTitle)
     }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val v = LayoutInflater.from(parent.context).inflate(R.layout.my_cv, parent, false)
        return ViewHolder(v)

        val myButton = v.findViewById<Button>(R.id.btn_A)!!

        myButton.setOnClickListener {
            customView = View.inflate(holder.itemView.context, R.layout.fragment_dialog, null)

                val builder = AlertDialog.Builder(holder.itemView.context)
                builder.setIconAttribute(R.attr.imgInfo)
                builder.setTitle(R.string.dialog_title)
                builder.setView(customView)
                builder.setPositiveButton(android.R.string.ok){ dialog, _ -> dialog.dismiss() }
                builder.show()
        }
    }
}

Solution

  • In Kotlin

    In Kotlin you cant implement onClickListener in ViewHolderClass directly. In Kotlin to achieve the same, you have to do onClickListener inside onBindViewHolder

    holder.myButton.setOnClickListener {
                //do your stuff here
    }
    

    or use init function

    // I'm not sure this is a correct method or not
    
    class MyRVAdapter : RecyclerView.Adapter<MyRVAdapter.ViewHolder>() {
    
    
        override fun getItemCount(): Int {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }
    
    
        override fun onBindViewHolder(holder: ViewHolder, position: Int) {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }
    
    
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyRVAdapter.ViewHolder {
            TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        }
    
        class ViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
            var myButton = itemView.findViewById(R.id.button) as Button
    
             // use any of the following declaratons
             // val myButton = itemView.findViewById(R.id.button) as Button
             // val myButton = itemView.findViewById<Button>(R.id.button)
             // var myButton = itemView.findViewById<Button>(R.id.button)
             // var myButton:Button = itemView.findViewById(R.id.button)
             // val myButton:Button = itemView.findViewById(R.id.button)
    
    
            // to avoid Expecting Member Declaration is showing in kotlin  use constructor
           // Expecting Member Declaration is showing because kotlin allows null declaration so a constructor or init is required to avoid this
            init {
                myButton.setOnClickListener{
                    //do your stuff here
                }
            }
    
        }
    }
    

    In Java

    onBindViewHolder will be executed whenever there is a change in data. So it is good to write the onClickListener in The ViewHolderClass.

    myButton.setOnClickListener {
                //do your stuff here
    }