Set onItemClickListener inside onBindViewHolder() with RecyclerView.Adapter
Asked Answered
B

5

11

I have a custom object :

Student.class

public class Student {
  private String name;
  private String age;

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  public String getAge() {
    return age;
  }

  public void setAge(String age) {
    this.age = age;
  }
}

Then I implement RecyclerView.Adapter like this :

MyAdapter.class

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {

  private Context context;
  private ArrayList<Student> students = new ArrayList<>();

  public MyAdapter(Context mContext, ArrayList<Student> mStudents) {
    this.context = mContext;
    this.students = mStudents;
  }

  @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(context).inflate(R.layout.item_row, parent, false);
    return new ViewHolder(v);
  }

  @Override public void onBindViewHolder(ViewHolder holder, int position) {

    final Student student = students.get(position);

    holder.name.setText(student.getName());
    holder.age.setText(student.getAge());

    holder.setClickListener(new ItemClickListener() {
      @Override public void onClickItem(int pos) {
        Toast.makeText(context, "CLICK : " + student.getName(), Toast.LENGTH_SHORT).show();
      }

      @Override public void onLongClickItem(int pos) {
        Toast.makeText(context, "LONG CLICK : " + student.getName(), Toast.LENGTH_SHORT).show();
      }
    });
  }

  @Override public int getItemCount() {
    return students.size();
  }

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

    private TextView name;
    private TextView age;
    private ItemClickListener mListener;

    public ViewHolder(View itemView) {

      super(itemView);
      name = (TextView) itemView.findViewById(R.id.tv_name);
      age = (TextView) itemView.findViewById(R.id.tv_age);

      itemView.setOnClickListener(this);
      itemView.setOnLongClickListener(this);
    }

    public void setClickListener(ItemClickListener listener) {
      this.mListener = listener;
    }

    @Override public void onClick(View view) {
      mListener.onClickItem(getLayoutPosition());
    }

    @Override public boolean onLongClick(View view) {
      mListener.onLongClickItem(getLayoutPosition());
      return true;
    }
  }

  public interface ItemClickListener {
    void onClickItem(int pos);

    void onLongClickItem(int pos);
  }
}

As you can see in onBindViewHolder(), I set onItemClickListener() for holder.

@Override public void onBindViewHolder(ViewHolder holder, int position) {

    final Student student = students.get(position);
    holder.name.setText(student.getName());
    holder.age.setText(student.getAge());

    holder.setClickListener(new ItemClickListener() {
      @Override public void onClickItem(int pos) {
        Toast.makeText(context, "CLICK : " + student.getName(), Toast.LENGTH_SHORT).show();
      }

      @Override public void onLongClickItem(int pos) {
        Toast.makeText(context, "LONG CLICK : " + student.getName(), Toast.LENGTH_SHORT).show();
      }
    });
  }

But I know onBindViewHolder() method will be called every time a new item scrolls into view. So call click listener inside onBindViewHolder() causes expensive operations inside it.

How can I resolve this problem?

Baudekin answered 22/12, 2015 at 4:36 Comment(2)
You cannot set a click listener on the holder object itself. Set it on one of the included view elements.Albemarle
so do that inside onCreateViewHolder instead of onBindViewHolderFrankish
S
8

You need to set on onClickListener() on the view of the ViewHolder i.e. itemView in your case. It will call the onClick() method as soon as you click the complete view i.e. root view (itemView in your case)

you can also set onClickListener() on the children of the root i.e. name and age.

inside ViewHolder(View itemView) constructor:

itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(mContext,"clicked="+ getPosition(),Toast.LENGTH_SHORT).show();         

                }
            });

Similarly you can call onLongClickListner() also. And name.setOnClickLisner() on child view too.

Stepparent answered 22/12, 2015 at 5:2 Comment(4)
wonder why there is no onitemclick lister for this. @Baqir, your answer worked.Brainard
Please also disclose the getPosition() method implementation. how are you having position inside ViewHolder constructorThynne
how to get the adapter data on that position?Nightie
getAdapterPosition() will return current item positionMartel
S
1

You can set event Onclick for specific audiences:

Eg:

 holder.layout.setClickListener(new ItemClickListener() {
  @Override public void onClickItem(int pos) {
    Toast.makeText(context, "CLICK : " + student.getName(), Toast.LENGTH_SHORT).show();
  }
Spokane answered 22/12, 2015 at 5:8 Comment(0)
F
1

You can implement onClickListener for the parent view like below:

//holder.view - parent layout inside recyclerView item
holder.view.setTag(position);
holder.view..setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            int pos = (int) v.getTag();
            Student student = students.get(pos);
            // Do your operation

        }
    });

OR

if you want to set onItemClickListener from activity/fragment where recyclerView is initialised, you can follow this link: http://www.littlerobots.nl/blog/Handle-Android-RecyclerView-Clicks/

Flatus answered 22/12, 2015 at 5:29 Comment(0)
K
1

Simplest way is holding single ItemClickListener inside your Adapter:

public class WalletListRecyclerAdapter extends RecyclerView.Adapter<WalletListRecyclerAdapter.ViewHolder> {
    private List<Wallet> wallets;
    private ItemClickListener itemClickListener;

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Wallet wallet = wallets.get(position);

        holder.root.setOnClickListener(v -> {
            if (itemClickListener != null)
                itemClickListener.onClick(holder.root, wallet);
        });
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        View root;

        public ViewHolder(View v) {
            super(v);
            root = v;
        }
    }


    public void setItemClickListener(ItemClickListener itemClickListener) {
        this.itemClickListener = itemClickListener;
    }

    public interface ItemClickListener {
        void onClick(View view, Wallet wallet);
    }
}

In Activity:

walletsAdapter = new WalletListRecyclerAdapter();
walletsAdapter.setItemClickListener((view, wallet) -> {
    Intent intent = new Intent(this, WalletActivity.class);
    intent.putExtra(Const.KEY_WALLET, wallet);
    startActivity(intent);
});
Knop answered 13/9, 2018 at 16:3 Comment(0)
F
0

replace this code,

        @Override public void onBindViewHolder (ViewHolder holder,int position){

            final Student student = students.get(position);
            holder.name.setText(student.getName());
            holder.age.setText(student.getAge());


            holder.v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(context, "CLICK : " + student.getName(), Toast.LENGTH_SHORT).show();
                }
            });

            holder.v.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View v) {
                    Toast.makeText(context, "CLICK : " + student.getName(), Toast.LENGTH_SHORT).show();
                    return false;
                }
            });
        }
Farina answered 20/2, 2018 at 12:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.