RecyclerView Part 3: Android RecyclerView OnClick

Continue with our series about RecyclerView, we known about basic element of a RecyclerView. Today we are going to make our RecyclerView’s items clickable, which was a trivial task with ListView. However, if you are just moving to use RecyclerView, you will find it is so complicated to implement such thing.

But, is it really complicated?

Android RecyclerView OnClick

First, refer to this question on StackOverflow and see what’s the problem?

Since the introduction of ListView, onItemClickListener has been problematic. The moment you have a click listener for any of the internal elements the callback would not be triggered but it wasn’t notified or well documented (if at all) so there was a lot of confusion and SO questions about it.

Given that RecyclerView takes it a step further and doesn’t have a concept of a row/column, but rather an arbitrarily laid out amount of children, they have delegated the onClick to each one of them, or to programmer implementation.

So, the idea is very simple, we assign the onClick handler to our view within the holder. Developers are totally free to have their own implementation with not only onClick, but also all other event triggers.

Sample Implementation

Please visit source code on GitHub of RecyclerViewCollection for details, here we assign the listener when we create the holder, so this method won’t be called over and over when the view is refreshed:

@Override public SimpleHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
 View view = getLayoutInflater().inflate(R.layout.view_item, viewGroup, false);
 view.setOnClickListener(new View.OnClickListener() {
  @Override public void onClick(View v) {
   int pos = mRecyclerView.getChildAdapterPosition(v);
   if (pos >= 0 && pos < getItemCount()) {
    Toast.makeText(OnClickListenerActivity.this, DataProvider.JAVA_BOOKS[pos], Toast.LENGTH_SHORT).show();
   }
  }
 });
 return new SimpleHolder(view);
}

We want to know the position of clicked item, here we use the method:

mRecyclerView.getChildAdapterPosition(v)  

to retrieve the position of item inside adapter.

And this is the result:

Recycler<em>3</em>OnClick

Another implementation is using getAdapterPosition() from RecyclerView.Holder:

static class SimpleHolder extends RecyclerView.ViewHolder {  
 TextView mTextView;
 public SimpleHolder(final View itemView) {
  super(itemView);
  this.mTextView = (TextView) itemView.findViewById(R.id.view_item_text);
  itemView.setOnClickListener(new View.OnClickListener() {
   @Override public void onClick(View v) {
    int pos = getAdapterPosition();
    Toast.makeText(itemView.getContext(), DataProvider.JAVA_BOOKS[pos], Toast.LENGTH_SHORT).show();
   }
  });
 }
}

Both methods are quite suitable for most typical usecases. Developers are free to create their own implementation. However, please pay attention to some points:

  • Do not create new object, especially onClick handler inside onBindViewHolder, as this method will be called many times when users scrolling.
  • Save and cache the onClick handler if possible. Use getAdapterPosition() from the Holder, or getChildAdapterPosition() from the adapter so you can pass the position/index of the item to the handler.