RecyclerView Item Click Listener the Right Way
Some Android developers wonder why Google created a view like Recyclerview without a click listener(given the fact that the deprecated ListView has an item click listener).
Because there is no standard way of setting a click listener, new developers tend to confuse on the right way of doing it. In this article, I will show you how to do it in a proper way using an example scenario.
Example Scenario
- There is a Recyclerview adapter with a Recyclerview with a list of items(Users in this case).
- What we want is that when an item is clicked, we get the item’s model(User) information and may be pass it to a second activity.
Project Creation
From Android Studio, create an empty android project(Select the Kotlin support option) and name your activity, MainActivity.
Do not bother much if you do not know Kotlin. It is just like Java(somehow).
- Delete the default ‘Hello World’ TextView in activity_main.xml .
- Add recyclerview and cardview dependencies in app level build.gradle file as shown below.
Add recyclerview in activity_main.xml where you removed the textview as shown below.
<android.support.v7.widget.RecyclerView
android:layout_width="match_parent"
android:id="@+id/usersList"
android:layout_height="match_parent"/>
Ok we are good to go. The assumption is that you have worked with the recyclerview(in Java) before and know how to create a recyclerview adapter.. Next, we create the model class containing username and phone.
Data model
data class User(var username:String,var phone:String)
Sweet Kotlin. Just the above line of code gives us access to a setter and getter under the hood and other methods like toString. Check more at https://kotlinlang.org/docs/reference/data-classes.html .
Next, we create our view holder and adapter. Pay attention here because it is the most important part of what this article addresses.
Recyclerview Adapter and view holder
- Create a new Kotlin file called RecyclerAdapter.kt
- Next we create our item_user.xml layout as follows
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView app:contentPaddingTop="5dp"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
app:contentPaddingBottom="5dp"
app:cardCornerRadius="4dp"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:gravity="center"
android:orientation="vertical"
android:layout_height="wrap_content">
<TextView
android:textColor="#000"
android:layout_width="wrap_content"
tools:text="Ngenge Senior"
android:id="@+id/username"
android:layout_height="wrap_content" />
<TextView
android:textColor="#fff"
android:layout_width="wrap_content"
tools:text="12345678"
android:id="@+id/phone"
android:layout_height="wrap_content" />
</LinearLayout>
</android.support.v7.widget.CardView>
The item_user has two textviews which holds the name and phone.
Next we create our view holder. As usual, our view holder has a constructor with an itemView as parameter and we get a reference to our views from item_user layout .
class MyHolder(itemView: View) : RecyclerView.ViewHolder(itemView)
{
val name = itemView.username
val phone = itemView.phone
}
Then we create our adapter with the list of users as a parameter. An adapter contains the list of users
class RecyclerAdapter(var users:MutableList<User>):RecyclerView.Adapter<MyHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, position: Int): MyHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user,parent,false)
return MyHolder(view)
}
override fun getItemCount(): Int {
return users.size
}
override fun onBindViewHolder(myHolder: MyHolder, position: Int) {
val user = users.get(position)
myHolder.name.text = user.username
myHolder.phone.text = user.phone
}
}
Item Click the bad way
Note that in onBindView, we can have access to the the current clicked item and thus open a new activity from here and pass our data..
myHolder.itemView.setOnClickListener {
//we can then create an intent here and start a new activity
//with our data
}
This will work perfectly but it is a bad practice because
- It is not a good practice opening an Activity from a viewholder context
- Note that onBindViewHolder is called as your views are populated during scrolling. Thus you will have numerous calls to setOnClickListener.
Let us fix it
The way that you should do is that you create an ItemClickListener interface with one method ontemClicked with parameter User.
- We then pass modify the Adapter’s constructor to take the users list and an OnItemClickListener interface
class RecyclerAdapter(var users:MutableList<User>, val itemClickListener: OnItemClickListener):RecyclerView.Adapter<MyHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, position: Int): MyHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_user,parent,false)
return MyHolder(view)
}
override fun getItemCount(): Int {
return users.size
}
override fun onBindViewHolder(myHolder: MyHolder, position: Int) {
val user = users.get(position)
myHolder.bind(users.get(position),itemClickListener)
}
}
- We also modify the the ViewHolder to have a bind function which takes a user and itemClick interface as follows.
fun bind(user: User,clickListener: OnItemClickListener)
{
name.text = user.username
phone.text = user.phone
itemView.setOnClickListener {
clickListener.onItemClicked(user)
}
}
This is all we have to do. We just have to implement the interface in our MainActivity .
MainActivity
We get access to our users recyclerview list and we create an adapter with hard coded user information.MainActivity implements OnItemClickListener interface..
Summary
The steps are simple
- Create an OnItemClickListener with a single onItemClicked method that takes a model object.
- Modify Adapter and pass a listener as its parameter
- Call itemView.setOnClickListener in created bind method
- Let your Activity implement interface.. We are done
The complete code can be found here… https://github.com/ngengesenior/RecyclerViewClickListener
Don’t forget to
Hit some claps and share.. Thank you