android – How can I set OnClickListener to two buttons in RecyclerView?-ThrowExceptions

Exception or error:

In my android app I have one activity to show a RecyclerView in which each row is composed by a TextView and 2 buttons. Just like that:

ListAdapter Layout

Well, following many explanations of internet I have made this Adapter:

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

    private LayoutInflater layoutInflater;
    protected Vector<List> lists;

    public ListAdapter(Context context, Vector lists) {
        layoutInflater = (LayoutInflater) 
context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.lists = lists;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = layoutInflater.inflate(R.layout.listadapter, null);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        List list = lists.elementAt(position);
        holder.name.setText(list.getName());
        //holder.delete.set HOW DO I GET BUTTON HERE?
    }

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

    public static class ViewHolder extends RecyclerView.ViewHolder 
implements View.OnClickListener {
        public TextView name;
        public Button edit;
        public Button delete;

        public ViewHolder(View itemView) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.listname);
            edit = (Button) itemView.findViewById(R.id.edit);
            delete = (Button) itemView.findViewById(R.id.delete);

            edit.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.edit:
                    break;
                case R.id.delete:
                    break;
                default:
                    break;
            }
        }
    }
}

I haven’t found examples of having 2 buttons (there are only examples of adding images) in each view of the recyclerview, as in the first image. I mean, guess I have 10 List elements in my RecyclerView, how can I have in each of them to one side a TextView with the name of the List and 2 buttons and handle clickListener?. As in the following image, which I have done by hand for you to see what I am talking about:

enter image description here

This is the activity that will show the recyclerView; don’t take it into account because I am pretty sure the way is wrong. I get lists information from sqlite database:

public class ShowListOfLists extends AppCompatActivity {

private RecyclerView recyclerView;
private RecyclerView.LayoutManager layoutManager;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_show_list_of_lists);
    LocalDB localDB = new LocalDB(this, "localBD", null, 1);
    Vector <List> ListAdapter = localDB.getAllPrivateList();

    recyclerView = (RecyclerView) findViewById(R.id.recyclerviewlistas);
    recyclerView.setAdapter(new ListAdapter(this, ListAdapter));
    layoutManager = new LinearLayoutManager(this);
    recyclerView.setLayoutManager(layoutManager);
}

A list have the following attributes:

-idList int
-name String
-Description String
-creationDate Date
-active int (0 or 1)
-deactivationDate Date

Thank you in advance.

/*******************************EDIT****************************************/

Thank to you I have been able to show the recyclerView and it works well. But I see that:

recyclerviewresult

Instead of that:

enter image description here

This the XML code and design of the adapter:

ListAdapter Layout

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@drawable/rectangle_bg"
android:orientation="horizontal"
android:weightSum="1"
android:layout_marginTop="5dp">

<TextView
    android:id="@+id/listname"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginTop="20dp"
    android:layout_weight="0.75"
    android:gravity="center_vertical"
    android:text="TextView"
    android:textSize="15sp"/>

<LinearLayout
    android:layout_width="0dp"
    android:layout_height="match_parent"
    android:layout_weight="0.25"
    android:gravity="end"
    android:orientation="vertical">

    <ImageButton
        android:id="@+id/delete"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:background="@android:color/transparent"
        android:contentDescription="Delete"
        app:srcCompat="@android:drawable/ic_menu_delete" />

    <ImageButton
        android:id="@+id/edit"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:background="@android:color/transparent"
        android:contentDescription="Edit"
        app:srcCompat="@android:drawable/ic_menu_edit" />

    </LinearLayout>

</LinearLayout>

And this is the XML of the recyclerview

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    tools:context="com.pc.kanayel.runoutof.ShowListOfLists"
    android:orientation="vertical"
    android:id="@+id/recyclerviewlistas">

</android.support.v7.widget.RecyclerView>
How to solve:

You just need to add some code to your ListAdapter. It is there, where you have to implement onClickListener. The code for your case should look something like the one below.

You can pass any parameter you need to. It depends on the functionality you want to achieve. Here I have demonstrated passing the order of item clicked inside of list.

Option 1 (power/performance efficient)

So, what does the code below actually mean? You have already created a ViewHolder and implemented OnClickListener. That is correct. Now you need to set OnClickListener to two buttons. But what these buttons will do when clicked is defined by the interface we created inside of ViewHolder.

When app will run RecyclerView will create as many ViewHolders as it is needs to fill the available screen with list items by calling onCreateViewHolder() method for each of viewholders. When you scroll up/down these ViewHolders will be reused. OnCreateViewHolder() is not called, only onBindViewHolder() is called to update the content of viewholder. The code below made so that, when ViewHolder is created it will also create an MyClickListener that will be used by OnClickListener of viewholder and when viewholder is reused it will not create new OnClickListener. It means that our method is performance efficient.

Option 2 (not efficient)

You could also setOnClickListener() inside of onBindViewHolder(). However, as I have mentioned in the paragraph above, this method is called every time you scroll to update the content of viewholder. Now it would create new OnClickListener object everytime. While Option 1 has OnClickListener on every ViewHolder and it reuses them.

Code for Option 1

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

    private LayoutInflater layoutInflater;
    protected Vector<List> lists;

    public ListAdapter(Context context, Vector lists) {
        layoutInflater = (LayoutInflater) 
        context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.lists = lists;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = layoutInflater.inflate(R.layout.listadapter, null);
        ViewHolder holder = new ViewHolder(view, new MyClickListener() {
            @Override
            public void onEdit(int p) {
                // Implement your functionality for onEdit here
            }

            @Override
            public void onDelete(int p) {
                // Implement your functionality for onDelete here
            }
        });
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        List list = lists.elementAt(position);
        holder.name.setText(list.getName());
    }

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

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

        MyClickListener listener;

        TextView name;
        Button edit;
        Button delete;

        public ViewHolder(View itemView, MyClickListener listener) {
            super(itemView);
            name = (TextView) itemView.findViewById(R.id.listname);
            edit = (Button) itemView.findViewById(R.id.edit);
            delete = (Button) itemView.findViewById(R.id.delete);

            this.listener = listener;

            edit.setOnClickListener(this);
            delete.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.edit:
                    listener.onEdit(this.getLayoutPosition());
                    break;
                case R.id.delete:
                    listener.onDelete(this.getLayoutPosition());
                    break;
                default:
                    break;
            }
        }
    }

    public interface MyClickListener {
            void onEdit(int p);
            void onDelete(int p);
    }
}

Edit for your second question

To make list items take all the width set the width of your recyclerview to match_parent. It is also better to make it a child view of some layout. For instance as given below.

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.pc.kanayel.runoutof.ShowListOfLists">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recyclerviewlistas"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

<RelativeLayout>

And change this code inside of your adapter:

View view = layoutInflater.inflate(R.layout.listadapter, null);

to this:

View view = layoutInflater.inflate(R.layout.listadapter, parent, false);

###

You can do simply like this:

@Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        List list = lists.elementAt(position);
        holder.name.setText(list.getName());
        holder.edit.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Do your stuff
                }
            });
        holder.delete.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Do your stuff
                }
            });
    }

Leave a Reply

Your email address will not be published. Required fields are marked *