Wiktor
Wiktor

Reputation: 925

RecyclerView onClickListener Setup Performance

so i tried to implement onClickListener for my RecyclerView for the first time and I've been wondering if what i did is actually worth doing. In my application i have different Recycler Views, and i don't need both onClickListeners and onLongClickListeners at the same time in most of them, so I wanted to do it so that i don't have to implement them both in my .setOnItemClickListener. I basically check which onClickListener is set up with enum mode, and then according to that i set my listeners in onCreateViewHolder. Does it even makes sense to do that? Or should i just implement both listeners and don't do what i did in my code?

public class FreindRecyclerViewAdapter extends RecyclerView.Adapter<FreindRecyclerViewAdapter.MyViewHolder> {

    private ClickListener clickListener ;
    private LongClickListener longClickListener;

    private Context context;
    private List<String> friends;
    private ListenerMode mode;

    public enum ListenerMode {NullMode, ShortClick, LongClick}

    public interface ClickListener {

        void onItemClick(int position, View v);

    }

    public interface LongClickListener {

        void onItemLongClick(int position, View v);

    }

    public void setOnItemClickListener(ClickListener clickListener) {
        this.clickListener = clickListener;
        mode = ListenerMode.ShortClick;
    }

    public void setOnLongItemClickListener(LongClickListener longItemClickListener) {
        this.longClickListener = longItemClickListener;
        mode = ListenerMode.LongClick;
    }

    public FreindRecyclerViewAdapter (Context context, List<String> friends) {

        this.context = context;
        this.friends = friends;
        this.mode = ListenerMode.NullMode;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view;
        view = LayoutInflater.from(context).inflate(R.layout.friend_item, viewGroup, false);
        final MyViewHolder myViewHolder = new MyViewHolder(view);

        if(mode == ListenerMode.ShortClick) {
            myViewHolder.itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    clickListener.onItemClick(myViewHolder.getAdapterPosition(), view);
                }
            });
        } else if (mode == ListenerMode.LongClick) {

            myViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() {
                @Override
                public boolean onLongClick(View view) {

                    longClickListener.onItemLongClick(myViewHolder.getAdapterPosition(), view);

                    return true;
                }
            });

        }



        return myViewHolder;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int position) {

        myViewHolder.friendName.setText(friends.get(position));


    }

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

    public static class MyViewHolder extends RecyclerView.ViewHolder {

        private TextView friendName;

        public MyViewHolder(View itemView) {
            super(itemView);

            friendName= itemView.findViewById(R.id.friendName_ID);

        }

    }

}

EDIT: Now that i think of it, i don't even know why it does work, like when i set up my RecyclerView, adapter and all in my code below, I first tell the adapter about the list I want to show on the screen in it's constructor recyclerViewAdapter = new FreindRecyclerViewAdapter(this, friends);, so this is when onCreateViewHolder is called for my views. So now when everything is created (ViewHolders) I call the function to set up the OnClickListener, which in my code adds different listeners according to the mode that is set up, and those listeners are added in onCreateViewHolder, which was already called, so why does RecyclerViewAdapter (and how does it know to) call the onCreateViewHolder again to add the listeners?

friends = new ArrayList<>();

        friends.add("Josh");
        friends.add("Mike");
        friends.add("Ashley");
        friends.add("Jess");


        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        recyclerView = findViewById(R.id.recyclerViewFriend_ID);
        recyclerViewAdapter = new FreindRecyclerViewAdapter(this, friends);
        recyclerView.setLayoutManager(linearLayoutManager);
        recyclerView.setAdapter(recyclerViewAdapter);

        DividerItemDecoration itemDecor = new DividerItemDecoration(this, linearLayoutManager.getOrientation());
        recyclerView.addItemDecoration(itemDecor);



        recyclerViewAdapter.setOnLongItemClickListener(new FreindRecyclerViewAdapter.LongClickListener() {
            @Override
            public void onItemLongClick(int position, View v) {
                Toast.makeText(FriendActivity.this, "Long Click. Position:" + Integer.toString(position), Toast.LENGTH_SHORT).show();
            }
        });

Upvotes: 1

Views: 431

Answers (1)

guipivoto
guipivoto

Reputation: 18677

It's ok but it can be better.

1) You are creating a click listener and long click listener for every position

You don't need to create a listener for every position like you are doing here:

myViewHolder.itemView.setOnClickListener(new View.OnClickListener() ...

and

myViewHolder.itemView.setOnLongClickListener(new View.OnLongClickListener() ...

Since they are performing the very similar action, you can create only one click and longclick listener and share with all views. To make that, move the itemView.setOnClickListener() and the itemView.setOnLongClickListener() to the ViewHolder class.

You need to save the position in the ViewHolder as well. So, they will be able to store their own position.

2) You don't need to create a enum

You don't need to create a enum to check if current mode (click or long click). Instead, you can just check if the variables are null, for example.

In the end, you can have a code like this:

public class FreindRecyclerViewAdapter extends RecyclerView.Adapter<FreindRecyclerViewAdapter.MyViewHolder> {

    private ClickListener clickListener ;
    private LongClickListener longClickListener;

    private Context context;
    private List<String> friends;

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

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

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

    public void setOnLongItemClickListener(LongClickListener longItemClickListener) {
        this.longClickListener = longItemClickListener;
    }

    @NonNull
    @Override
    public MyViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
        View view;
        view = LayoutInflater.from(context).inflate(R.layout.friend_item, viewGroup, false);
        return new MyViewHolder(view, i, clickListener, longClickListener);;
    }

    @Override
    public void onBindViewHolder(@NonNull MyViewHolder myViewHolder, int position) {
        myViewHolder.friendName.setText(friends.get(position));
    }

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

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

        private TextView friendName;
        private int position;

        public MyViewHolder(View itemView, int position) {
            super(itemView);
            friendName = itemView.findViewById(R.id.friendName_ID);
            this.position = position;
            if (clickListener != null) {
                itemView.setOnClickListener(this);
            }
            if (longClickListener != null) {
                itemView.setOnLongClickListener(this);
            }
        }

        @Override
        public void onClick(View view) {
            if (clickListener != null) {
                clickListener.onItemClick(position, view);
            }
        }

        @Override
        public boolean onLongClick(View view) {
            if (longClickListener != null) {
                longClickListener.onItemLongClick(position, view);
                return true;
            } else {
                return false;
            }
        }
    }
}
  • Note that now, each view holder knows its own position
  • View holder implements the regular View.OnClickListener and View.LongClickListener. So, you don't need to instantiate a new listener for every position.
  • If you want to enable the click, call FreindRecyclerViewAdapter.setOnItemClickListener(object);
  • If you want to enable the long click, call FreindRecyclerViewAdapter.setOnLongItemClickListener(object);
  • If you want to disable any of them, don't call the methods above or just call them passing null as parameter. If you check the code in MyViewHolder, you can see that any action is performed when those listeners are null

Hope I could help and share more ways to achieve what you want!!!

Upvotes: 1

Related Questions