7

Edit

As It is a genericAdapter not simple one and I know the methods to add click listener. And it is not a good practice to do this in onCreateViewHolder. So that's why I need a better suggestion

I have created a Generic Adapter for RecyclerView in android. Now I want some suggestion to improve it. And how could I add clickListener to it.

GenericAdapter.java

public abstract class GenericAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;
    private ArrayList<T> items;
    private OnRecyclerItemClicked onRecyclerItemClicked;

    public abstract RecyclerView.ViewHolder setViewHolder(ViewGroup parent);

    public abstract void onBindData(RecyclerView.ViewHolder holder, T val);

    public GenericAdapter(Context context, ArrayList<T> items){
        this.context = context;
        this.items = items;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder holder = setViewHolder(parent);
        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        onBindData(holder,items.get(position));
    }

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

    public void addItems( ArrayList<T> savedCardItemz){
        items = savedCardItemz;
        this.notifyDataSetChanged();
    }

    public T getItem(int position){
        return items.get(position);
    }

    public void setOnRecyclerItemClicked(OnRecyclerItemClicked onRecyclerItemClicked){
        this.onRecyclerItemClicked = onRecyclerItemClicked;
    }

    public interface OnRecyclerItemClicked{
        void onItemClicked(View view,int position);
    }
}

And Call it like

adapter = new GenericAdapter<MyModelClass>(context,listOfModelClass) {
                @Override
                public RecyclerView.ViewHolder setViewHolder(ViewGroup parent) {
                    final View view = LayoutInflater.from(context).inflate(R.layout.item_recycler_view, parent, false);
                    AViewHolder viewHolder = new AViewHolder(context, view);
                    return viewHolder;
                }

                @Override
                public void onBindData(RecyclerView.ViewHolder holder1, MyModelClass val) {
                        MyModelClass currentCard = val;

                        AViewHolder holder = (AViewHolder)holder1;
                        holder.cardNumber.setText(currentCard.getDisplayNumber());
                        holder.cardHolderName.setText(currentCard.getCardHolderName());
                }
            };
            mRecyclerView.setAdapter(adapter);

Now how and where could I add a click listener. As adding click listener to onBindData is an overhead. Need suggestion.

Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
  • Possible duplicate of [RecyclerView onClick](http://stackoverflow.com/questions/24471109/recyclerview-onclick) – OneCricketeer Aug 02 '16 at 07:42
  • One way I have seen is your view holder class implements `View.OnClickListener` – OneCricketeer Aug 02 '16 at 07:42
  • Related: http://stackoverflow.com/questions/24471109/recyclerview-onclick – Sufian Aug 02 '16 at 07:47
  • 1
    what's wrong with adding listener inside `onCreateViewHolder`? – pskink Aug 02 '16 at 07:59
  • 1
    onCreateViewHolder call everytime when you need to initialize view.So If I have 200 items in a RecyclerView. It will called for 200 times – Zar E Ahmer Aug 02 '16 at 08:03
  • And It will also be apply to full item. If I want to add click on textView rather than full item – Zar E Ahmer Aug 02 '16 at 08:05
  • 2
    wrong, `onCreateViewHolder` will be called few times (lets say 10 times or so): that is the number of visible items in your `RecyclerView`, this is the whole idea of `ViewHolder`s – pskink Aug 02 '16 at 08:07
  • for such adapter you can use [this](https://gist.githubusercontent.com/pskink/cd3bbdd742b5b1905a790c76831b5d85/raw/89a41acded0889028be48e1f669562046cf66126/MatchableRVArrayAdapte%2520(pure%2520RecyclerView%2520style,%2520no%2520implicit%2520TextView%2520mapping)) generic adapter, with this concrete implementation: http://pastebin.com/kCcBuV7G – pskink Aug 02 '16 at 08:44
  • @pskink you are right about it. It will be only called for currently visible items – Zar E Ahmer Aug 02 '16 at 10:21
  • so if you run my code i hope you know where to add `OnClickListener` ? – pskink Aug 02 '16 at 10:42
  • @pskink I appreciate your help . Now I understand where to put OnClickListener. but curious about your matches method. can you share how you call matches – Zar E Ahmer Aug 02 '16 at 11:51
  • just return true if your item matches the prefix dtring, false otherwise, and no, you dont call it: it will call you, but it is for filtering purposes, i mean where you call `adapter.getFilter().filter(...)` from some `EditText` / `SearchView` etc – pskink Aug 02 '16 at 11:52
  • Thanks a lot @pskink you gave the right answer. I accept your comments as the right answer. – Zar E Ahmer Aug 02 '16 at 12:54
  • and `matches` method could simply have for example: `return value.getDisplayName().toLowerCase().contains(lowerCasePrefix);` – pskink Aug 02 '16 at 12:55

4 Answers4

3

Have you tried adding a ViewHolder and add the clicklistener to it

Now GenericAdapter.java.

public abstract class GenericAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private Context context;
    private List<T> items;
    private OnRecyclerItemClicked onRecyclerItemClicked;

    public abstract RecyclerView.ViewHolder setViewHolder(ViewGroup parent , OnRecyclerItemClicked onRecyclerItemClicked);

    public abstract void onBindData(RecyclerView.ViewHolder holder, T val);

    public abstract OnRecyclerItemClicked onGetRecyclerItemClickListener();

    public GenericAdapter(Context context, List<T> items){
        this.context = context;
        this.items = items;
        onRecyclerItemClicked = onGetRecyclerItemClickListener();
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        RecyclerView.ViewHolder holder = setViewHolder(parent , onRecyclerItemClicked);
        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        onBindData(holder,items.get(position));
    }

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

    public void setItems( ArrayList<T> savedCardItemz){
        items = savedCardItemz;
        this.notifyDataSetChanged();
    }

    public T getItem(int position){
        return items.get(position);
    }

    public interface OnRecyclerItemClicked{
        void onItemClicked(View view,int position);
    }
}

And calling it like this

GenericAdapter<CreditCardItemBO> adaptering = new GenericAdapter<CreditCardItemBO>(mContext,new ArrayList<CreditCardItemBO>()) {
            @Override
            public RecyclerView.ViewHolder setViewHolder(ViewGroup parent, OnRecyclerItemClicked onRecyclerItemClicked) {
                final View view = LayoutInflater.from(mContext).inflate(R.layout.item_save_credit_card, parent, false);
                CreditCardViewHolder viewHolder = new CreditCardViewHolder(mContext, view,onRecyclerItemClicked);
                return viewHolder;
            }

            @Override
            public void onBindData(RecyclerView.ViewHolder holder, CreditCardItemBO val) {

            }

            @Override
            public OnRecyclerItemClicked onGetRecyclerItemClickListener() {
                return new OnRecyclerItemClicked() {
                    @Override
                    public void onItemClicked(View view, int position) {

                    }
                };
            }
        };
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300
Santa Teclado
  • 186
  • 10
0

You can add the listener in the activity you have declared the RecyclerView:

recyclerView.addOnItemTouchListener(new RecyclerTouchListener(this, recyclerView, 
   new RecyclerTouchListener.ClickListener() {
        @Override
        public void onClick(View view, int position) {
                //Handle the action
            }
        }

        @Override
        public void onLongClick(View view, int position) {

        }

    }));
Santa Teclado
  • 186
  • 10
  • I want item click listener not on whole recyclerView click – Zar E Ahmer Aug 02 '16 at 07:47
  • @Nepster click listener for only certain items? Or for all items? The above is a solution for all items, with the `int position` telling which item is clicked. – Sufian Aug 02 '16 at 07:48
  • @Nepster the above is called when individual items are clicked. If you want listeners for different components in an item you will have to do that in the onBindViewHolder method of the adapter. The method in the earlier answer also enables you handle the events in the activity and not in the adapter. – Santa Teclado Aug 03 '16 at 08:34
  • @Santa your answer is right. But the reason for why I have created GenericAdapter to get rid of extra coding . I want to handle it in Adapter. And now I have added the listener to constructor and whenever I created a ViewHolder I must have to implement that listener. – Zar E Ahmer Aug 03 '16 at 09:38
  • @Nepster have tried adding a ViewHolder and add the clicklistener to it: – Santa Teclado Aug 03 '16 at 10:21
0

I have implemented ViewHolder in Santa solution like this:

public class EmployeeViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    private TextView employeeName;
    private BaseRecyclerAdapter.OnRecyclerItemClicked mOnRecyclerItemClicked;

    public EmployeeViewHolder(View view, BaseRecyclerAdapter.OnRecyclerItemClicked onRecyclerItemClicked) {
        super(view);
        employeeName = (TextView) view.findViewById(R.id.employee_name);
        mOnRecyclerItemClicked = onRecyclerItemClicked;
        view.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        mOnRecyclerItemClicked.onItemClicked(view, getAdapterPosition());
    }

    public TextView getEmployeeName() {
        return employeeName;
    }
}

If you need the context ad it in to constructor as a parameter.

MeLean
  • 3,092
  • 6
  • 29
  • 43
0

I have created a generic adapter, the aar and the sources are at this url:

it's easy usage:

RecyclerAdapter<Customer> mAdapter = new RecyclerAdapter(customerList, CustomerViewHolder.class);

add attach listener (lambda sample)

RecyclerItemClickListener.affectOnItemClick(mRecycler, (position, view1) -> { 
 //action
});

see Url link more details

Maxime Jallu
  • 2,352
  • 1
  • 10
  • 12