Android RecyclerView onItemClickListener & getAdapterPosition(): A Better Way

A lighter way to get that thing done smoothly.

Rohit Surwase
HackerNoon.com
Published in
3 min readAug 17, 2018

--

Photo by Émile Perron on Unsplash

Update 1: Included lambda functions as an alternative.
Update 2: Included a link to Implementation example App on GitHub.

TL;DR
Instead of creating a custom ItemClickListener interface to getAdapterPosition() inside your Activity/Fragment/View and end up creating multiple Anonymous Classes under the hood for each item. Better pass the RecyclerView.ViewHolder using view.setTag() inside your ViewHolder and then getAdapterPosition() (…and many other things) from view.getTag() i.e. ViewHolder’s object inside your Activity/Fragment/View.
Implementation example App on GitHub

The Most Popular Way; The Problem

I know you must have already found a way to get onItemClickListener() for your RecyclerView Adapter. But sometimes the way we think is not always the correct or a better way. Whenever anyone tries to find a way to getAdapterPosition() inside their Activity/Fragment/View. He or she comes across the well-known pattern of creating a custom interface with view and position as the parameters.

public interface ItemClickListener {
void onItemClick(View view, int position);
}

Later, we initialize the ItemClickListener instance using the public setter.

private ItemClickListener onItemClickListener;...public void setItemClickListener(ItemClickListener clickListener) {
onItemClickListener = clickListener;
}

OR… by passing the ItemClickListener instance via constructor.

Constructor of RecyclerViewAdapter

And finally we pass our view and adapter position to the listener.

And we know the rest of the part very well.
Most of the articles out there depict the same thing. But there is a problem.

When we say itemView.setOnClickListener(new View.OnClickListener()…

It creates an Anonymous inner class under the hood which implements our ItemClickListener listener.

class AnonymousItemClickListener implements ItemClickListener{
@Override
public void onItemClick(View view, int position) {

}
}

And we end up creating and initializing multiple Anonymous inner classes under the hood just for a click listener.

new AnonymousItemClickListener(){
@Override
public void onItemClick(View view, int position) {

}
};

I used to do the same. Because that is what we get to see all over the internet.

Update:
As suggested by in the comments section, we can use Java8’s Lambda functions to get rid of anonymous class creation at compile time. Lambda functions work with SAM types (interfaces with Single Abstract Method) and the reason it does not create anonymous inner class is the InvokeDynamic instruction, introduced in Java 7.
So with Lambdas, we can convert above function as below:

itemView.setOnClickListener(view -> onItemClickListener.onItemClick(view, getAdapterPosition());

And for some reasons you can not use Java8’s Lambda functions then go ahead as following way is still a better option for you.

A Better Way; The Solution

But, recently I got a suggestion from a colleague to implement it in a better and lighter way. Let’s see how we can get adapter position, item id (…and many other things) inside our Activity/Fragment/View.

So, instead of creating new custom interface, we will use View.OnClickListener and initialize it in the way we used to do.

private View.OnClickListener onItemClickListener;...public void setItemClickListener(View.OnClickListener clickListener) {
onItemClickListener = clickListener;
}

And we will pass the instance of ViewHolder via itemView to the listener using setTag().

private class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(View itemView) {
super(itemView);
itemView.setTag(this);
}
}

In this way, we do not need to create Anonymous inner class as we can directly give the reference of onItemClickListener

private class MyViewHolder extends RecyclerView.ViewHolder {
public MyViewHolder(View itemView) {
super(itemView);
itemView.setTag(this);
itemView.setOnClickListener(onItemClickListener);
}
}

Finally we can get adapter position and item id (…and many other things) inside our Activity/Fragment/View from the ViewHolder instance.

RecyclerView.ViewHolder viewHolder = (RecyclerView.ViewHolder) view.getTag();int position = viewHolder.getAdapterPosition();
// viewHolder.getItemId();
// viewHolder.getItemViewType();
// viewHolder.itemView;

Simple! Isn’t it?
Let me know your views and suggestions about this in the comment section.

If you still have some doubts, here is the source code of the Implementation example App on GitHub.

Thanks for reading!
Rohit Surwase

If you like the article, clap clap clap 👏👏👏 as many times as you can.

LIKED SO MUCH! Medium allows up to 50 claps.
Also post a Tweet on Twitter.

Let’s be the friends on LinkedIn, Medium, Twitter and GitHub.

Latest stories by me

--

--

Rohit Surwase
HackerNoon.com

Techie by Birth. Writer by Hobby. Observer by Nature. Unpredictable by Character. Android Developer (Google Certified) by Profession.