RecyclerView onClick

726,929

Solution 1

As the API's have radically changed, It wouldn't surprise me if you were to create an OnClickListener for each item. It isn't that much of a hassle though. In your implementation of RecyclerView.Adapter<MyViewHolder>, you should have:

private final OnClickListener mOnClickListener = new MyOnClickListener();

@Override
public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int viewType) {
    View view = LayoutInflater.from(mContext).inflate(R.layout.myview, parent, false);
    view.setOnClickListener(mOnClickListener);
    return new MyViewHolder(view);
}

The onClick method:

@Override
public void onClick(final View view) {
    int itemPosition = mRecyclerView.getChildLayoutPosition(view);
    String item = mList.get(itemPosition);
    Toast.makeText(mContext, item, Toast.LENGTH_LONG).show();
}

Solution 2

Here is a better and less tightly coupled way to implement an OnClickListener for a RecyclerView.

Snippet of usage:

RecyclerView recyclerView = findViewById(R.id.recycler);
recyclerView.addOnItemTouchListener(
    new RecyclerItemClickListener(context, recyclerView ,new RecyclerItemClickListener.OnItemClickListener() {
      @Override public void onItemClick(View view, int position) {
        // do whatever
      }

      @Override public void onLongItemClick(View view, int position) {
        // do whatever
      }
    })
);

RecyclerItemClickListener implementation:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;


public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
  private OnItemClickListener mListener;

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

    public void onLongItemClick(View view, int position);
  }

  GestureDetector mGestureDetector;

  public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
    mListener = listener;
    mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            return true;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            View child = recyclerView.findChildViewUnder(e.getX(), e.getY());
            if (child != null && mListener != null) {
                mListener.onLongItemClick(child, recyclerView.getChildAdapterPosition(child));
            }
        }
    });
}

  @Override public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
    View childView = view.findChildViewUnder(e.getX(), e.getY());
    if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
      mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
      return true;
    }
    return false;
  }

  @Override public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) { }

  @Override
  public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
}

Solution 3

I do it in this way, without undue classes, detectors etc. Simple code inside our adapter. Especially better solution for longClick than presented before.

public class PasswordAdapter extends RecyclerView.Adapter<PasswordAdapter.ViewHolder> {
    private static ClickListener clickListener;

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
        TextView name;

        public ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            itemView.setOnLongClickListener(this);
            name = (TextView) itemView.findViewById(R.id.card_name);
        }

        @Override
        public void onClick(View v) {
            clickListener.onItemClick(getAdapterPosition(), v);
        }

        @Override
        public boolean onLongClick(View v) {
            clickListener.onItemLongClick(getAdapterPosition(), v);
            return false;
        }
    }

    public void setOnItemClickListener(ClickListener clickListener) {
        PasswordAdapter.clickListener = clickListener;
    }

    public interface ClickListener {
        void onItemClick(int position, View v);
        void onItemLongClick(int position, View v);
    }
}

Then inside fragment or activity, just hit:

PasswordAdapter mAdapter = ...;

mAdapter.setOnItemClickListener(new PasswordAdapter.ClickListener() {
    @Override
    public void onItemClick(int position, View v) {
        Log.d(TAG, "onItemClick position: " + position);
    }

    @Override
    public void onItemLongClick(int position, View v) {
        Log.d(TAG, "onItemLongClick pos = " + position);
    }
});

Solution 4

Check out a similar question @CommonsWare's comment links to this, which implements the OnClickListener interface in the viewHolder.

Here's a simple example of the ViewHolder:

    TextView textView;//declare global with in adapter class

public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

      private ViewHolder(View itemView) {
            super(itemView);
            itemView.setOnClickListener(this);
            textView = (TextView)view.findViewById(android.R.id.text1);

      }

      @Override
      public void onClick(View view) {
            Toast.makeText(view.getContext(), "position = " + getLayoutPosition(), Toast.LENGTH_SHORT).show();

         //go through each item if you have few items within recycler view
        if(getLayoutPosition()==0){
           //Do whatever you want here

        }else if(getLayoutPosition()==1){ 
           //Do whatever you want here         

        }else if(getLayoutPosition()==2){

        }else if(getLayoutPosition()==3){

        }else if(getLayoutPosition()==4){

        }else if(getLayoutPosition()==5){

        }

        //or you can use For loop if you have long list of items. Use its length or size of the list as 
        for(int i = 0; i<exampleList.size(); i++){

        }


      }
  }

The Adapter then looks like this:

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view =LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);

        return new ViewHolder(view);
    }

Solution 5

Based on Jacob Tabak's answer (+1 for him), I was able to add onLongClick listener:

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;

public class RecyclerItemClickListener implements RecyclerView.OnItemTouchListener {
    public interface OnItemClickListener {
        void onItemClick(View view, int position);

        void onItemLongClick(View view, int position);
    }

    private OnItemClickListener mListener;

    private GestureDetector mGestureDetector;

    public RecyclerItemClickListener(Context context, final RecyclerView recyclerView, OnItemClickListener listener) {
        mListener = listener;

        mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            @Override
            public boolean onSingleTapUp(MotionEvent e) {
                return true;
            }

            @Override
            public void onLongPress(MotionEvent e) {
                View childView = recyclerView.findChildViewUnder(e.getX(), e.getY());

                if (childView != null && mListener != null) {
                    mListener.onItemLongClick(childView, recyclerView.getChildAdapterPosition(childView));
                }
            }
        });
    }

    @Override
    public boolean onInterceptTouchEvent(RecyclerView view, MotionEvent e) {
        View childView = view.findChildViewUnder(e.getX(), e.getY());

        if (childView != null && mListener != null && mGestureDetector.onTouchEvent(e)) {
            mListener.onItemClick(childView, view.getChildAdapterPosition(childView));
        }

        return false;
    }

    @Override
    public void onTouchEvent(RecyclerView view, MotionEvent motionEvent) {
    }

    @Override
    public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
    }
}

Then you can use it like this:

recyclerView.addOnItemTouchListener(new RecyclerItemClickListener(getActivity(), recyclerView, new RecyclerItemClickListener.OnItemClickListener() {
    @Override
    public void onItemClick(View view, int position) {
        // ...
    }

    @Override
    public void onItemLongClick(View view, int position) {
        // ...
    }
}));
Share:
726,929
Admin
Author by

Admin

Updated on January 16, 2021

Comments

  • Admin
    Admin over 3 years

    Has anyone using RecyclerView found a way to set an onClickListener to items in the RecyclerView? I thought of setting a listener to each of the layouts for each item but that seems a little too much hassle I'm sure there is a way for the RecyclerView to listen for the onClick event but I can't quite figure it out.

  • ian.shaun.thomas
    ian.shaun.thomas over 9 years
    This seems to go the wrong direction though. If you need to re-use a recyclerview in another fragment/activity, the adapter/viewholder are now defining the logic of the clicks instead of whatever is containing them. The clicks should really be handled directly or indirectly by the containing instance. It seems that a touch listener is the only effective way to go about this.
  • NT_
    NT_ over 9 years
    This will not provide any clue about which button or view (within the item) was clicked. But for overall item click, this is fine.
  • Piyush Kukadiya
    Piyush Kukadiya over 9 years
    what if i want to delete a row on its click ?
  • Piyush Kukadiya
    Piyush Kukadiya over 9 years
    what if i want to delete a row on its click ?
  • Jacob Tabak
    Jacob Tabak over 9 years
    You should have no issue deleting a row on click. The OnItemClickListener gives you the position of the view in the adapter so you can delete it.
  • Matthias Loibl
    Matthias Loibl over 9 years
    Of all the versions I tried, this is the one I got working. But is it ok, to do it that way? Or is there a better way, like best practice?
  • Fifer Sheep
    Fifer Sheep over 9 years
    As far as I could tell, this was the only way. Check this out for more details! stackoverflow.com/a/24933117/1508887
  • Jacob Tabak
    Jacob Tabak over 9 years
    ngen's comment is correct - if you want to attach an onClick listener to a specific item within the item view, you should probably do that in your adapter, in onBindViewHolder, or in your viewholder itself.
  • Gak2
    Gak2 over 9 years
    One problem with this method is when you are doing something that takes a few hundred milliseconds like starting an activity. When the item is clicked, and it has a clicked animation there is a noticeable delay between clicking and seeing the animation.
  • Diffy
    Diffy over 9 years
    Can someone please explain the role of mGestureDetector.onTouchEvent(e) here and how it helps in determining the click?
  • wasyl
    wasyl over 9 years
    This solution feels extremely clunky, there's some delay when processing the 'click' and the feel isn't just ok
  • hash
    hash over 9 years
    How can i open new fragment from inside onclick method?
  • Andrew Orobator
    Andrew Orobator over 9 years
    Why is your code in OnInterceptTouchEvent instead of OnTouchEvent?
  • Lo-Tan
    Lo-Tan over 9 years
    I like this answer better than the one you linked. Who wants to write a gesture listener and hit box detection to handle this. Google--
  • EpicPandaForce
    EpicPandaForce about 9 years
    @tencent I don't see how that is the problem. If the ViewHolder itself contains all information in regards to what data is selected when the element itself is clicked, then the only responsibility of the container is the display of N elements, rather than that of handling the selection of a specific i-th element out of the N elements. The ListView was already problematic if you had to create a list of more complicated objects than just simple rows. What if you need to handle different events depending on where you click the item in the ListView? You're screwed. Here, you have each listeners.
  • Jigar
    Jigar about 9 years
    getChildPosition(view) is deprecated method
  • Jigar
    Jigar about 9 years
    we can use getChildLayoutPosition(view) instead.
  • Cris
    Cris about 9 years
    Sorry, how do I use the setItemChecked(position) with your implementation?
  • leafcutter
    leafcutter about 9 years
    This approach worked well for me - it means you can handle clicks in the activity rather than inside the grid view
  • Raghunandan
    Raghunandan about 9 years
    @JacobTabak can we handle both click on individual views in adapter and item click listener. The touch is intercepted by onTouchListener. If i have both then i have both fire listeners one on view and the other on the row item
  • Arūnas Bedžinskas
    Arūnas Bedžinskas about 9 years
    @JacobTabak Note: view.getChildPosition(childView) is deprecated now
  • zacharia
    zacharia about 9 years
    @JacobTabak currently i add a method onLongPress(MotionEvent e) in the interface & in the GestureDetector i override onLogpress. (@Override public void onLongPress(MotionEvent e) { listener.onLongPress(e); }) i want to pass the child view and position , not the motion event to the listener like onItemClick.... How can i implement that..
  • milosmns
    milosmns about 9 years
    Took me a while to adapt to my app, and align and format code to Java/Android standards, but eventually it worked fine.
  • Victor Odiah
    Victor Odiah about 9 years
    getChildAdapterPosition(view) is a more reliable option than getChildLayoutPosition(view) getChildLayoutPosition(view) may not be equal to Item's adapter position if there are pending changes in the adapter which have not been reflected to the layout yet.
  • Dominik
    Dominik about 9 years
    Could anyone explain to me why this solution with the GestureDetector is supposed to be a better solution than just using "setOnClickListener" inside of onBindViewHolder() in the adapter to the according element? This way at least I need less code than with the GestureDetector solution. Thanks for an explanation.
  • Jon
    Jon about 9 years
    How do you add an animation for the long click?
  • Apurva
    Apurva about 9 years
    What do I use instead of view.getChildPosition as it has been depreciated?
  • Vince
    Vince almost 9 years
    Do you mind telling which classes are your snippets in? onClick(), belonging to OnClickListener can be attached to ANY View. The whole question here is which! Please make an effort, a method is not only identified by a name, but also at least by a class. If you don't say your code is to be added to the adapter, your answer does not really help.
  • Ced
    Ced almost 9 years
    Should the onClick method be in the fragment that holds the RecyclerView ? Because you reference the mRecyclerView in your MyOnClickListener class. Where did you get the reference to that object ?
  • Muhammad Riyaz
    Muhammad Riyaz almost 9 years
    Simply use interfaces to avoid complexity. See gist.github.com/riyazMuhammad/1c7b1f9fa3065aa5a46f
  • D4rWiNS
    D4rWiNS almost 9 years
    in my case holder.itemView.setOnClickListener(..)
  • D4rWiNS
    D4rWiNS almost 9 years
    it is named 'itemView' instead of 'view' in my case, just saying for the beginners, some of them dont understand what are they copying, and can't figure out why doesnt work
  • ingsaurabh
    ingsaurabh almost 9 years
    @Eng.Fouad click effect is not working by using this, although if we set click listener in adapter click effect works any solution to this
  • Brandon
    Brandon almost 9 years
    Where can I give you money. 4 hours of searching and then I read your post. Thanks for the time you took to post this.
  • Edward Quixote
    Edward Quixote almost 9 years
    I just found out that this approach raises a fatal performance issue. There's great delay before the user could scroll the list(considering a list of several items). The user has to hold for sometime before scrolling in order for the RecyclerView to scroll, otherwise, it's just responding to the tough events.
  • Edward Quixote
    Edward Quixote almost 9 years
    Question: The onBindViewHolder(...) returns an int position. Which position is this in regards to the RecyclerView? Is it the Layout Position or Adapter Position?
  • AdamMc331
    AdamMc331 almost 9 years
    I agree with @EpicPandaForce on this one. I also came to upvote this answer after reading the section of Commonsware's book on handling clicks in RecyclerViews It has worked great for me so far.
  • rgv
    rgv almost 9 years
    This sounds stupid but, does this have any memory or efficiency like issue? Because we are assigning the click listener every time a view is being drawn right?
  • nommer
    nommer almost 9 years
    instead of OurAdapter.clickListener i think Marurban means PasswordAdapter.clickListener and instead of TrainingAdapter.ClickListener(), should be PasswordAdapter.ClickListener(). Other than that, great solution Marurban! worked for me
  • Paolo Rotolo
    Paolo Rotolo almost 9 years
    You should also override public void onRequestDisallowInterceptTouchEvent (boolean disallowIntercept){}
  • Rajiev Timal
    Rajiev Timal almost 9 years
    getChildPosition is now deprecated, please see my answer below and gist.github.com/RTimal/ddf4040cfba28b461ec7
  • Rajiev Timal
    Rajiev Timal almost 9 years
    getChildPosition is now deprecated and this does not tell you which view was clicked. Please see my answer below and gist.github.com/RTimal/ddf4040cfba28b461ec7
  • Anjula
    Anjula almost 9 years
    this method will not show the click effect on that item. Please follow below link plus.google.com/+AnjulaSashika/posts/D9jtomxRyDr
  • Bubunyo Nyavor
    Bubunyo Nyavor almost 9 years
    Its the layout position
  • Sir NIkolay Cesar The First
    Sir NIkolay Cesar The First almost 9 years
    @Raghav yes every time view is being bind a new click listener is assigned, but this is the standard flow. But the mOnItemClickListener is created only once for the adapter just the view and its position are different on each item click ;)
  • jwir3
    jwir3 over 8 years
    +1 for the fact that you specifically pointed out another author's method is less tightly coupled, and linked to it as the first line of your answer.
  • Rashad.Z
    Rashad.Z over 8 years
    onItemClick listener is also being activated on long click.
  • markfknight
    markfknight over 8 years
    Thanks, this really helped me understand how to implement OnClickListener Interfaces
  • Renato Probst
    Renato Probst over 8 years
    This is the best solution because we usually need a lot of properties from activity/fragment on our onItemClickListener, and theres no sense to call it direct from the viewholder (i would have to create a custom constructor for each adapter). By the way, your code is a little extense, i suggest you to cut it to the most important part (setOnItemClickListener).
  • Francois Dermu
    Francois Dermu over 8 years
    getChildPosition(View) is deprecated. Use public int getChildAdapterPosition (View child) instead. Full documentation here
  • Naruto Uzumaki
    Naruto Uzumaki over 8 years
    You should also override onRequestDisallowInterceptTouchEvent event.
  • Dmitry
    Dmitry over 8 years
    For some reason it doesn't return a clicked view. In my case I click on a checkbox but given view is something different. The way I check: view.getId() == R.id.selection
  • Dmitry
    Dmitry over 8 years
    For some reason it doesn't return a clicked view. In my case I click on a checkbox but given view is something different. The way I check: view.getId() == R.id.selection
  • Dmitry
    Dmitry over 8 years
    I figured out the view is a topmost Layout for a list_item.xml. How can I know on which exactly view a click was?
  • Dmitry
    Dmitry over 8 years
    I figured out the view is a topmost Layout for a list_item.xml. How can I know on which exactly view a click was?
  • Nasz Njoka Sr.
    Nasz Njoka Sr. over 8 years
    for me this seem to only apply for the last visible item not the clicked item
  • Nasz Njoka Sr.
    Nasz Njoka Sr. over 8 years
    getChildPosition() is decapitated
  • Vikram Singh
    Vikram Singh over 8 years
    getChildPosition() method is deprecated. Use getChildAdapterPosition(View) or getChildLayoutPosition(View).
  • Vikram Singh
    Vikram Singh over 8 years
    getChildPosition() method is deprecated. Use getChildAdapterPosition(View) or getChildLayoutPosition(View).
  • Mehul Joisar
    Mehul Joisar over 8 years
    getChildPosition is deprecated getChildAdapterPosition will give wrong position when you scroll the view. getChildLayoutPosition will give correct position.
  • veritas
    veritas over 8 years
    @JacobTabak why this method is better than attaching onClickListener on individual Items ??
  • GuillermoMP
    GuillermoMP over 8 years
    This is a common bad practice because it looks way too easy. You are creating a new inner listener each time an object is binded (and each item in a recycler can be bound lots of times) which is bad for a)performance b)garbage collection. Instead you should create ONE listener somewhere (in the viewholder, in the adapter, in the upper fragment or activity) and just add it to the items in the viewholder constructor on in onCreateViewHolder. This has the added complexity of having to figure out which item was clicker, but can be solved easily via tags or adding more info to the holder.
  • Hubert Grzeskowiak
    Hubert Grzeskowiak about 8 years
    The whole point of a view holder is for it to hold the references to containing elements. If you use findViewById in onCreateViewHolder you're working around the intentional pattern.
  • devunwired
    devunwired about 8 years
    This implementation introduces a few awkward edge cases since the touch events are divorced from the view they represent. Among them is click timing. GestureDetector supports long press by default, so a longer click is consumed and never reported—long press should be shut off. Another is the requirement of setting the view's visual clickability separately. This implementation doesn't connect with enabling the view to show this state to the user.
  • Edmond Tamas
    Edmond Tamas about 8 years
    This solution seems the best for me, but how does this differ from @bolot 's answer in therms of performance? He has implemented View.OnClickListener directly on the ViewHolder class, which than spits out the onClick method separately. Which would be the best solution?
  • stuckj
    stuckj about 8 years
    findViewById is only being used on view holder creation here (hence onCreateViewHolder). The view holder is intended to prevent finding the view every time an item is bound to the holder, not on initial creation.
  • Winster
    Winster almost 8 years
    I had to use v.setClickListener(this) in ViewHolder constructor to make it work. But longclicklistener is still not working
  • 0101100101
    0101100101 almost 8 years
    This unnecessarily creates a new OnClickListener constantly while scrolling and thus shouldn't be used. Use getAdapterPosition() to access the item position from the click listener.
  • Bubunyo Nyavor
    Bubunyo Nyavor almost 8 years
    @0101100101 where do you do this.
  • 0101100101
    0101100101 almost 8 years
    @orignMaster ViewHolder has that method, so it can be used in any listener there.
  • Gilberto Ibarra
    Gilberto Ibarra almost 8 years
    ViewHolder must be static for the best performance. this is not a good answer.
  • iYonatan
    iYonatan almost 8 years
    Where MyOnClickListener class should be written?
  • K Neeraj Lal
    K Neeraj Lal almost 8 years
    getPosition() is deprecated, use getAdapterPosition() or getLayoutPosition() instead.
  • tanghao
    tanghao over 7 years
    public MyViewHolder onCreateViewHolder(final ViewGroup parent, final int position) is confusing. The second argument is viewType instead of position. The position argument is only available in onBindViewHolder(MyViewHolder holder, int position)
  • zholmes1
    zholmes1 over 7 years
    Why are you taking a Context as a constructor parameter when you can just use recyclerView.getContext()?
  • ChrisR
    ChrisR over 7 years
    In the ViewHolder Class, when I set the onLongClick to return false, I fire off a longclick and both onItemClick and onItemLongClick get called. When I set the onLongClick to return true, only the correct click gets called, but the adapter doesnt update the recyclerview when I delete an item on a long click. Any Ideas as to what I'm doing wrong?
  • Justin Mitchell
    Justin Mitchell over 7 years
    RecyclerView is pretty powerful even though you have to do the legwork yourself to handle the data and deal with any changes. +1 for the answer, perfecto!
  • BladeCoder
    BladeCoder over 7 years
    Another reason to avoid the Gesture Detector solution is that it doesn't work with keypad navigation.
  • BladeCoder
    BladeCoder over 7 years
    The static clickListener creates a memory leak. Declare the listener as non-static and bind it to the ViewHolder instead.
  • BladeCoder
    BladeCoder over 7 years
    You should use getAdapterPosition() instead of getLayoutPosition()
  • Zac
    Zac over 7 years
    I have a checkbox in the card and when I use this class, for some reason holder.checkbox.setOnCheckedChangeListener does not get called. How to sort of bring the checkbox "to front"?
  • Sumit Jha
    Sumit Jha over 7 years
    return true from onLongClick to consume the event and avoid toast appearing for both click and long click.
  • W.K.S
    W.K.S over 7 years
    container should be WeakReference<View>. The Context (your activity) contains a reference to the recycler view, which contains a reference to the view holder which, in this case, has a reference back to the context.
  • Sir NIkolay Cesar The First
    Sir NIkolay Cesar The First over 7 years
    @W.K.S the container is different for each item and is needed to assign the onclick listener to it. The RecyclerView should recycle the ViewHolder if it's needed...
  • Renato
    Renato over 7 years
    This solution does not consider focus navigation (keyboard navigation), something that a simple click listener could solve (click listeners encapsulates keyboard enter, D-Pad center, and other pointer events). This solution is not accessible as it can only handle touch events and shouldn't be used. Consider using a simple click listener with getChildAdapterPosition() to retrieve position.
  • Ajit Kumar Dubey
    Ajit Kumar Dubey about 7 years
    When user click on button which is inside item view, how to handle that event?
  • Nigel Savage
    Nigel Savage about 7 years
    this is a good simple approach for differentiating the row / item from the sub-items
  • user2695433
    user2695433 about 7 years
    Can you let me know if I had 2 buttons How can I get to know which button is clicked inside the Recyclerview?
  • N Sharma
    N Sharma about 7 years
    How to send mRecyclerView in an adapter ?
  • Rissmon Suresh
    Rissmon Suresh almost 7 years
    it's bad practice to implement click listener inside an onCreateView().
  • Marurban
    Marurban almost 7 years
    You can check its id inside onClick method v.getId()
  • peterkodermac
    peterkodermac almost 7 years
    Can confirm, this library is great! Very easy to use, good job!
  • Pablo Escobar
    Pablo Escobar almost 7 years
    Total disaster. You'll get the item clicked position of the item which was just blinded not the item you click
  • Mykola Tychyna
    Mykola Tychyna almost 7 years
    Great example to kill app performance and create memory overuse! With this example you just need scroll to create hundreds of useless objects, that in a moment will be useless and have to be accessed as garbige. @NoobDogg is right. No ClickListeners haven't to be created at onBindView. A click listener have to be created once in onCreateView (or holder constructor), and exists while we need screen with this adapter.
  • Sir NIkolay Cesar The First
    Sir NIkolay Cesar The First over 6 years
    @MykolaTychyna how will you perform click listener for an item, when you don't have it's position on onCreateView?! You need to know which item was clicked and have it's position so you can access it's data. You are just not right
  • Mykola Tychyna
    Mykola Tychyna over 6 years
    @Sir NIkolay Cesar The First please at first notice the problem of creation of huge numbers of objects (ClickListeners) with very short life time. Its overhead and antipattern - always! When you are running onCreateViewHolder your are running ViewHolder constructor, and inside it you have to create click lstener. Inside of method onClick you can call getAdapterPosition and perform with this index get on your data collection. In this case ClickListeners will be created as much as ViewHolders.
  • Trevor
    Trevor over 6 years
    To get the item position inside onCreateView (so that the click listener may be bound there), you simply need to have another property inside your ViewHolder that captures the index, or some other metadata that provides a 'handle' to that item, during onBindViewHolder. This is all I do. There is no need for repeated binding of listeners, and there is no need to jump through any hoops to calculate the clicked item. I'm absolutely staggered that none of these answers illustrate this.
  • Trevor
    Trevor over 6 years
    Binding the click listener during ViewHolder creation is the correct way as it avoids repeated listener assignments that would happen if you did it in onBindViewHolder. However, the trick being missed here is that I also use ViewHolder to retain an ID (or some other 'handle' metadata) that provides means to determine the clicked item. This is instead of all the pointless jumping through hoops to calculate clicked Item position. So all I do is bind a click listener in the holder ctor, and have the holder also capture meta information that provides a pointer of some sort to the underlying data.
  • Trevor
    Trevor over 6 years
    I find it absolutely staggering that despite this being so simple to do as described above, some of the highest voted answers here advocate use of MotionEvents and various other bloat.
  • Shirish Herwade
    Shirish Herwade over 6 years
    where do this 'onClick' method belongs? How did you get 'mRecyclerView' inside that onClick method?
  • Nick Sikrier
    Nick Sikrier over 6 years
    Setting click for any part of view in RecyclerView.ViewHolder leads to incorrect processing of touch events. For example, if you would like to implement SnapHelper for such RecyclerView, OnClickListener will override OnTouchListener in SnapHelper and last one won't receive MotionEvent.ACTION_DOWN events.
  • Amir Ziarati
    Amir Ziarati about 6 years
    what if the list has one item ? :/ i need recycler view click not item click
  • Amir Ziarati
    Amir Ziarati about 6 years
    doesnt work on a list with one item. its item click rather than recycler click.
  • Nikson
    Nikson about 6 years
    @nhaarman can you help me to solve this stackoverflow.com/questions/50115252/…
  • Pemba Tamang
    Pemba Tamang about 6 years
    where does this 'onClick' method belong? How did you get 'mRecyclerView' inside that onClick method?...
  • mshsayem
    mshsayem about 6 years
    @PembaTamang @Shirish Herwade You can override the method onAttachedToRecyclerView() of your adapter, then you will get a reference to the recyclerView; set it to a member variable say mRecyclerView. And now, you got it.
  • RoCkDevstack
    RoCkDevstack about 6 years
    How to pass the holder values through intent?
  • RoCkDevstack
    RoCkDevstack about 6 years
    How do you pass the holder values through intent?
  • Kennedy Nyaga
    Kennedy Nyaga about 6 years
    getAdapterPosition() replaces getPosition()
  • Arslan Maqbool
    Arslan Maqbool almost 6 years
    its click on the on the whole item. if i have one more button in this to perform functionality on this. it's also treat like as itemview click listener?
  • user1872384
    user1872384 over 5 years
    why is it so confusing to just add a listener =.='' it's so much easier on iOS... Adding delegate
  • AJW
    AJW about 5 years
    @BladeCoder Can you provide an example of how best to bind the clickListener to the ViewHolder? Just assign it to the itemView of the clickListener?
  • BladeCoder
    BladeCoder about 5 years
    @AJW The simplest way is to initialize the listener early and pass it as argument to the Adapter constructor and then the ViewHolder constructor.
  • O-9
    O-9 about 5 years
    that mRecyclerView was bothering me (how do you access it inside adapter-class), so I modified the Adapter constructor Adapter(..., RecyclerView rcv) to accept the owner RV. Then I am able to access the element's position [inside onClick] final int pos = myAdapter.this.myRecView.getChildAdapterPosition(view); and it seems to work...
  • Sa'ad Abdurrazzaq
    Sa'ad Abdurrazzaq almost 5 years
    Hi mate, can you help me to solve this issue please.. I've been stuck many days here stackoverflow.com/questions/57068321/…
  • nhaarman
    nhaarman almost 5 years
    @Sa'adAbdurrazzaq No, and I'd appreciate it if you wouldn't ping people like this.
  • Roman Gherta
    Roman Gherta over 4 years
    Hi Jimmy, the rule was that you should not pass view references to the viewmodel if you don't want memory leaks. In this case we are passing viewmodel to adapter that is managing views. I tried to think of situations under which this would create a memory leak but unfortunately I cannot think of any. VIewmodel lifecycle is larger than adapter and thus I do not think this would create a memory leak. If you have something on your mind, do let me know. I do not claim the absolute truth.
  • Sir NIkolay Cesar The First
    Sir NIkolay Cesar The First over 4 years
    Ok I editted my answer as I see that some people are still liking it ;)
  • CoolMind
    CoolMind over 4 years
    You need to set clickListener with a method or constructor.
  • Egor
    Egor almost 4 years
    I'm listened that it is bad solution because you create too many listeners.
  • Gopal Singh Sirvi
    Gopal Singh Sirvi almost 4 years
    It will create as many listeners as many items are visible on the screen. As we scroll the unused listeners will be garbage collected
  • Gopal Singh Sirvi
    Gopal Singh Sirvi almost 4 years
    Other way is to add a tag to the view, we can use the position number as tag and create only one listener and set it to all items. Then the position will be found out by getting the tag
  • Mr-IDE
    Mr-IDE over 3 years
    There are some other ways to get a reference to the full list row View, using the ViewHolder: 1 - ViewGroup rowView = (ViewGroup)viewHolder.imageIV.getParent(). 2 - View rowView = viewHolder.itemView. Then you can add onClickListeners to these rowViews.
  • Hamburg is nice
    Hamburg is nice over 3 years
    Because MANY people asked this: If I understand correctly, the onClick() method is inside the class "MyOnClickListener" he used for the click listener. The reference to mRecyclerView must have been passed as an argument to the constructor or so (which he unfortunately didn't show). please correct me if I'm wrong!
  • Liker777
    Liker777 over 3 years
    Thanks, that is even better than the initial answer. Works fine for me
  • Charan
    Charan over 3 years
    I have the same approach, but an item click is not triggered until a 2-3 extra clicks on the same line item. Any idea why extra clicks are required?
  • Ehsan Rosdi
    Ehsan Rosdi almost 3 years
    This worked for me. Easier to understand for newbie like me. :) Thanks.
  • Chucky
    Chucky over 2 years
    This is great. Thanks for bringing it to my attention - I normally trust most practices that come directly from Google. Do you know if the approach is any different when using an MVVM architecture? Also, it appears to be called a Primary/Detail Flow now when creating a new project!
  • Chucky
    Chucky over 2 years
    I gave it a whirl, and it doesn't seem to cause any issue with my MVVM architected app. I use an ItemViewModel as the .tag object of the item view. Not sure if this is best practice but works for me for now.
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • clic
    clic over 2 years
    getAdapterPosition() is deprecated: "This method is confusing when adapters nest other adapters. If you are calling this in the context of an Adapter, you probably want to call getBindingAdapterPosition() or if you want the position as RecyclerView sees it, you should call getAbsoluteAdapterPosition()"
  • NightStorm
    NightStorm over 2 years
    Whats no position?
  • Gastón Saillén
    Gastón Saillén over 2 years