Srinivas Nahak
Srinivas Nahak

Reputation: 1866

Getting error while deleting recyclerview items

I know it's a very old question but even after referring a lot of solutions nothing could solve my issue . Actually I'm trying to remove items of recyclerview on longclick but I'm getting following error .

By the way I'm not getting any error while deleting the last item but when I'm trying to delete any other item after deleting other than last item I'm getting the following error.

Error:

java.lang.ArrayIndexOutOfBoundsException: length=12; index=-1
                                                                    at java.util.ArrayList.remove(ArrayList.java:401)
                                                                    at community.infinity.message.MessageAdapter$1$1$1$1.run(MessageAdapter.java:219)
                                                                    at android.os.Handler.handleCallback(Handler.java:725)
                                                                    at android.os.Handler.dispatchMessage(Handler.java:92)
                                                                    at android.os.Looper.loop(Looper.java:137)
                                                                    at android.app.ActivityThread.main(ActivityThread.java:5041)
                                                                    at java.lang.reflect.Method.invokeNative(Native Method)
                                                                    at java.lang.reflect.Method.invoke(Method.java:511)
                                                                    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
                                                                    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
                                                                    at dalvik.system.NativeStart.main(Native Method)

My Code:

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


 Message message = mMessages.get(position);
 holder.setMessage(message.getMessage());

 holder.msgContainer.setOnLongClickListener(view -> {
      int position = holder.getAdapterPosition();

 if (position != RecyclerView.NO_POSITION) {
 mMessages.remove(position);
 notifyItemRemoved(position);
 notifyItemRangeChanged(position, mMessages.size());
 }

        return false;
    });

 }

}
}

Upvotes: 0

Views: 1070

Answers (2)

Anton Makov
Anton Makov

Reputation: 845

Personally I used to have the click listener outside of the adapter(in the fragment/activity) in

    public void onBindViewHolder(ViewHolder holder, int position)
    {
        //I'm saving here the position of the current item
        holder.rootView.setTag(position);

        //you set the listener functionality from the fragment/activity by sending 
        //to the constructor of your adapter
        holder.setLongClickListener(mListener);

        //init other fields of your item
        ...
    }

    // a function that will responsible to update the list without the deleted item
    public void setData(List<Data> data)
    {
         mData = data;
         notifyDataSetChanged();
    }
}

fragment/activity

your activity/fragment should implement the interface long click listener

public class MyFragment extends Fragment implements View.LongClickListener
{
   ...

   public boolean onLongClick(View view) 
   {
         int selectedIndex = (int)view.getTag();
         mData.remove(selectedIndex);
         mAdapter.setData(mData);
         return true;
   }
}

Don't forget to initialize the adapter with this, it needs your onClickListener implementation.

Upvotes: 0

Ben P.
Ben P.

Reputation: 54194

There's two problems here.

First, there's no need to call notifyItemRangeChanged() after you call notifyItemRemoved(). The call to notifyItemRemoved() will adjust the rest of the data set correctly.

Second, holder.getAdapterPosition() will sometimes return NO_POSITION (defined as -1). This will happen when the view holder knows that it was previously bound to an item that is no longer in the adapter, and hasn't been re-bound yet. Since you just called notifyItemRemoved(holder.getAdapterPosition()), the holder's adapter position has been marked as invalid and will now be returned as -1.

If you absolutely must call notifyItemRangeChanged(), re-write your code as follows:

int position = holder.getAdapterPosition();

if (position != RecyclerView.NO_POSITION) {
    mMessages.remove(position);
    notifyItemRemoved(position);
    notifyItemRangeChanged(position, mMessages.size());
}

Upvotes: 3

Related Questions