Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Remove a item from a RecyclerView (ViewHolder has the onClick but adapter has the dataset)

I want to delete items from a recyclerview when pressing a view which is in the items.

The situation: Having a list made using a RecyclerView with a dataset and a ViewHolder which has a onClick on a view for deleting the item from the list, I need to know which item has been clicked on the ViewHolder and communicate it to the Adapter, because the Adapter has the dataset. Inside the ViewHolder I can know which item has been pressed with this method: getAdapterPosition(), so it seems to be easy to know which item to delete.

The problem: ViewHolder is a subclass inside the RecyclerView.Adapter, and the Adapter has the dataset, so I'm trying to understand which is the best way for the viewholder to communicate the Adapter that must delete the Item which has been clicked.

State of the art: I can see some questions here in Stack Overflow, some of them old, some of them more new, for example this: Android RecyclerView addition & removal of items but the solution doesn't clarify how to communicate the Adapter that must delete the item. Probably the user was doing it using static fields or something, but it is not a good way of achieving this. And I can't see other ways explained in other questions.

This is a sample from the official Recycler guide where you can see that the ViewHolder is nested inside the Adapter and hasn't access to it: https://developer.android.com/guide/topics/ui/layout/recyclerview.html

public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
    private String[] mDataset;

    // Provide a reference to the views for each data item
    // Complex data items may need more than one view per item, and
    // you provide access to all the views for a data item in a view holder
    public static class ViewHolder extends RecyclerView.ViewHolder {
        // each data item is just a string in this case
        public TextView mTextView;
        public ViewHolder(TextView v) {
            super(v);
            mTextView = v;
        }
    }

    // Provide a suitable constructor (depends on the kind of dataset)
    public MyAdapter(String[] myDataset) {
        mDataset = myDataset;
    }

    // Create new views (invoked by the layout manager)
    @Override
    public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
                                                   int viewType) {
        // create a new view
        TextView v = (TextView) LayoutInflater.from(parent.getContext())
                .inflate(R.layout.my_text_view, parent, false);
        ...
        ViewHolder vh = new ViewHolder(v);
        return vh;
    }

    // Replace the contents of a view (invoked by the layout manager)
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        // - get element from your dataset at this position
        // - replace the contents of the view with that element
        holder.mTextView.setText(mDataset[position]);

    }

    // Return the size of your dataset (invoked by the layout manager)
    @Override
    public int getItemCount() {
        return mDataset.length;
    }
}
like image 473
NullPointerException Avatar asked Oct 23 '25 22:10

NullPointerException


1 Answers

I like the RecyclerView example by BigNerdRanch because they have a custom ViewHolder with a method (bindCrime() in the example) which is called from onBindViewHolder(). This method takes an item from the data list and sets all the Views depending on the item's content.

You could use a similar method, let's call it bindData(), and pass in not only the item from the data list but also [an anonymous instance of] a custom callback, let's call it ViewHolderCallback, which is in fact just some interface:

interface ViewHolderCallback{
    void itemWasClicked(int position);
}

Then onBindViewHolder() could look like this:

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    // - get element from your dataset at this position
    // - replace the contents of the view with that element
    holder.bindData(mDataset[position], new ViewHolderCallback(){

        @Override
        public void itemWasClicked(int position){
             // remove the item 
        }
    });
}

...and bindData() like this:

void bindData(String text, ViewHolderCallback callback){
    mTextView.setText(text);
    itemView.setOnClickListener(new View.OnClickListener(){
         
        @Override
        public void onClick(View view){
             callback.itemWasClicked(getAdapterPosition()); 
        }
    });
}
like image 169
Bö macht Blau Avatar answered Oct 25 '25 11:10

Bö macht Blau



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!