How to Improve RecyclerView’s Event Listener

Luqman Hakim
Qasir
Published in
5 min readJun 13, 2022

There are numerous ways to display lists on the screen in Android programming. We frequently employ ListView and RecyclerView widgets. However, if you’re creating a dynamic list of content, the RecyclerView is a great way to boost the device’s performance. Even though we are utilizing RecyclerView, poor code application can influence performance. We need to understand how RecyclerView works inside before we can discuss how to improve the event listener.

A. How RecyclerView works

When working with a RecyclerView Adapter, you should be familiar with the following four terms:

1. ItemViewType: Type of view based on the position for reuse/recycle.

2. ViewHolder: the parent class that controls layout inflation and the use of child views. onCreateViewHolder is responsible for the creation, recycling, and inflation of ViewHolders based on the item view type supplied by getItemViewType(…).

3. Count: the method that will be called multiple times to determine the maximum size of the list. In most cases, it returns the size of the dataset that was used to create views in the adapter.

4 Bind ViewHolder: connects data to the ViewHolder’s child views. Binding view holders are handled by the public function onBindViewHolder(…).

It is an example to illustrate how it works for a better understanding. Let’s imagine we have a RecyclerView with 30 items on the list, but only 5 of them are visible at first. RecyclerView causes the adapter to run the onCreateViewHolder function to initialize the view and the onBindViewHolder function to bind the data when constructing the showing item view. You can see that item x till item 5 represents a visible item on the screen in the illustration.

When scrolling down the process, item x becomes un-visible on screen and will be stored in the collection of scrapped views. And you have item 6 visible on the screen. A “scrapped” view is a collection view that is still attached to its parent RecyclerView but that has been marked for removal or reuse.

Before item 7 becomes visible when we scroll a second time, the recycler view will take a view from the collection of scrapped views and use the onBindViewHolder function to bind the new data instead of using the onCreateViewHolder function to construct a view. The view which is loaded from scrapped view is called a dirty view.

Now, the dirty view gets recycled and is relocated to the new item in the queue which has to be displayed on the screen i.e item 7. You can see the detailed explanation at https://blog.mindorks.com/how-does-recyclerview-work-internally.

B. Bad Event Listener Implementation

Knowing how RecyclerView works, we can see why using code like this is a bad idea:

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.itemView.setOnClickListener {
// do something
}
}

Because onBindViewHolder() is called every time a view needs to show on the screen, it is the most expensive block of code in the adapter, and great attention must be made to ensure performance. One of the specific measures is that slow code, such as interfaces (onClick events, for example), should be placed in the ViewHolder initialization.

The initiation of the event listener must happen at the moment of creating the view holder process.

C. Enhance Event Listener

Improving the listener is as simple as moving the implementation when the view holder is created like this:

class ViewHolder(
private val binding: ViewItemBinding
) : RecyclerView.ViewHolder(binding.root) {

init {
binding.textName.setOnClickListener {
// do something
}
}
}

You can declare an event listener on the view holder init block. In some cases, the view holder creates a separate class with an adapter. If you want to provide data at a given position, it can be impossible. To solve that you can use a callback to provide the adapter position of the view holder.

Create an interface callback on the adapter.

interface ViewHolderClickListener {
fun onClick(position: Int)
}

After that, you set a callback in the adapter property.

// in adapter  
val callback: ViewHolderClickListener? = null
override fun onCreateViewHolder(...): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ViewItemBinding.inflate(inflater, parent, false)
// passing to view holder
return ViewHolder(binding, callback)
}

and passing it to the view holder constructor.

// in view holder
class ViewHolder(
binding: ViewItemBinding,
callback: ViewHolderClickListener?
) : RecyclerView.ViewHolder(view.root) {
init {
binding.textName.setOnClickListener {
callback?.onClick(adapterPosition)
}
}
}

So in the activity class, you can get the object by adding a function in an adapter like

// adapter function
getObject(position: Int): Object {
return list[position]
}
// in activity
adapter = RecyclerAdapter()
adapter.callback = object: ViewHolderClickListener {
override fun onClick(position: Int) {
val data = adapter.getObject(position)
// do something with data
}
}

You can also assign the event listener in the apply block like this:

// in adapter  
val callback: ViewHolderClickListener? = null
override fun onCreateViewHolder(...): ViewHolder {
val inflater = LayoutInflater.from(parent.context)
val binding = ViewItemBinding.inflate(inflater, parent, false)
return ViewHolder(binding).apply {
binding.textName.setOnClickListener {
val object = getObject(adapterPosition)
callback?.onClick(object)
}
}
}

Since you’re using function scope (apply), you don’t need to pass a callback to the view holder. And one more advantage of using this approach is that you can get data directly from the adapter.

Conclusion

Using a Recycler View is important in optimizing performance, but there are still possible problems when we implement an incorrect way to handle click events inside the list. By properly implementing the event listener inside the view holder, we can prevent performance loss due to the click event listener being recycled along with the view holder, causing unnecessary overhead and potentially slowing down the recycler view.

References

https://medium.com/androiddevelopers/for-my-next-trick-i-will-write-about-onclick-45e0a6881c8a

https://oozou.com/blog/a-better-way-to-handle-click-action-in-a-recyclerview-item-60

https://blog.mindorks.com/how-does-recyclerview-work-internally

https://medium.com/@nileshsingh/understanding-recyclerview-part-1-the-basics-a7bd07cfae93

--

--