Android: Recycler view item fast clicking it crash the application

Viewed 1810

I have search a lot what I did is created a list of items simple number and having check box Which is checked and unchecked, So when I tap fast fast on list it crash and generate ArrayIndexOutOfBound Exception

So I don't know what is I am doing wrong

here is my code

adapter class

  class SingleListItemHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

private TextView mItemDate, mFontSizeCategory;
    private ImageView isChecked, isTrack, isUnChecked;
    private int fontSize = 13;
SingleListItemHolder(View v) {
    super(v);
    mFontSizeCategory = (TextView) v.findViewById(R.id.tv_font_size_category);
    mItemDate = (TextView) v.findViewById(R.id.tv_recycler_view_list_header);
    isChecked = (ImageView) v.findViewById(R.id.iv_recycler_view_list_item_selected);
    isUnChecked = (ImageView) v.findViewById(R.id.iv_recycler_view_list_item_unselected);
    isTrack = (ImageView) v.findViewById(R.id.iv_track);
    v.setOnClickListener(this);
    this.setIsRecyclable(false);
}

@Override
public void onClick(View v) {
    mSingleItemListModels.get(pos).setSelected(false);
    notifyItemChanged(pos, mSingleItemListModels.get(pos));
    pos = getAdapterPosition();
    mSingleItemListModels.get(pos).setSelected(true);
    notifyItemChanged(pos, mSingleItemListModels.get(pos));
}
4 Answers
pos = getAdapterPosition();

move above

mSingleItemListModels.get(pos).setSelected(false);

You are getting -1 Position in getAdapterPosition() because when u are click fast it some time throw the -1 position

You can check this out

if (pos != RecyclerView.NO_POSITION) {
//Do your setting part
}

Change this code

@Override
public void onClick(View v) {
    mSingleItemListModels.get(pos).setSelected(false);
    notifyItemChanged(pos, mSingleItemListModels.get(pos));
    pos = getAdapterPosition();
    mSingleItemListModels.get(pos).setSelected(true);
    notifyItemChanged(pos, mSingleItemListModels.get(pos));
}

Code to

@Override
public void onClick(View v) {
    mSingleItemListModels.get(pos).setSelected(false);
    notifyItemChanged(pos, mSingleItemListModels.get(pos));
    pos = getAdapterPosition();
     if (pos != RecyclerView.NO_POSITION) {
        mSingleItemListModels.get(pos).setSelected(true);
        notifyItemChanged(pos, mSingleItemListModels.get(pos));
     }
}

You have to get the item before using pos = getAdapterPosition();

@Override
public void onClick(View v) {

    pos = getAdapterPosition();


    mSingleItemListModels.get(pos).setSelected(false);
    notifyItemChanged(pos, mSingleItemListModels.get(pos));
    mSingleItemListModels.get(pos).setSelected(true);
    notifyItemChanged(pos, mSingleItemListModels.get(pos));
}

You are misusing getAdapterPosition. It's not a great idea to use it to get the index of the current displayed item. Even more bad that it may also return -1 if you have called a adapter change (which you did twice with notifyItemChanged).

See the docs for it here

Note that if you've called notifyDataSetChanged(), until the next layout pass, the return value of this method will be NO_POSITION.

The value of NO_POSITION is -1. So instead of implementing the ClickListener to your RecyclerView.ViewHolder you should implement it in the onBindViewHolder because there you have the current index.

Use it here

 @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
       // the position will be the correct one
       // but don't store the position in a class field 
       // since it may change during scrolling
    }
Related