The problem is the recyclerView recycle mode, which assigns your ViewHolder elements non-displayable elements that will be displayed on the screen. I would not suggest you bind your logic based on the ViewHolder object, as in all of the above answers. This will really cause you problems. You should build logic based on the state of the data object, not the ViewHolder Object, because you will never know when it will be processed.
Suppose you saved state boolean isSelected in a ViewHolder for verification, but if it is true, then the new item will have the same state when this ViewHolder is recycled.
The best way to do this is to hold any state in the DataModel. In your case, only a boolean value is selected .
Example example for example
package chhimwal.mahendra.multipleviewrecyclerproject; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.support.v7.widget.CardView; import android.widget.TextView; import java.util.List; public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { private Context mContext; private List<DataModel> mRViewDataList; public MyRecyclerViewAdapter(Context context, List<DataModel> rViewDataList) { this.mContext = context; this.mRViewDataList = rViewDataList; } @Override public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.item_recycler_view, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.bindDataWithViewHolder(mRViewDataList.get(position)); } @Override public int getItemCount() { return mRViewDataList != null ? mRViewDataList.size() : 0; } public class ViewHolder extends RecyclerView.ViewHolder { private TextView textView; private LinearLayout llView; private DataModel mDataItem=null; public ViewHolder(View itemView) { super(itemView); llView=(LinearLayout)itemView.findViewById(R.id.ll_root_view); textView = (TextView) itemView.findViewById(R.id.tvItemName); cvItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) {
As @Gabriel explained in a comment,
What if you want to select one item at a time?
In this case, again, you should not save the selected state of the element in the ViewHolder object, since it becomes recycled and causes problems. For this, it is better to have an int selectedItemPosition field in the Adapter class not ViewHolder . The following code snippet shows it.
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { private Context mContext; private List<DataModel> mRViewDataList; //variable to hold selected Item position private int mSelectedItemPosition = -1; public MyRecyclerViewAdapter(Context context, List<DataModel> rViewDataList) { this.mContext = context; this.mRViewDataList = rViewDataList; } @Override public MyRecyclerViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); View view = inflater.inflate(R.layout.item_recycler_view, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(ViewHolder holder, int position) { holder.bindDataWithViewHolder(mRViewDataList.get(position),position); } @Override public int getItemCount() { return mRViewDataList != null ? mRViewDataList.size() : 0; } public class ViewHolder extends RecyclerView.ViewHolder { private TextView textView; private LinearLayout llView; private DataModel mDataItem=null; public ViewHolder(View itemView) { super(itemView); llView=(LinearLayout)itemView.findViewById(R.id.ll_root_view); textView = (TextView) itemView.findViewById(R.id.tvItemName); cvItemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //Handling for background selection state changed int previousSelectState=mSelectedItemPosition; mSelectedItemPosition = getAdapterPosition(); //notify previous selected item notifyItemChanged(previousSelectState); //notify new selected Item notifyItemChanged(mSelectedItemPosition); //Your other handling in onclick } }); } //This is clean method to bind data with viewHolder. Do all dirty things on View based on dataItem. //Must be called from onBindViewHolder(),with dataItem. In our case dataItem is String object. public void bindDataWithViewHolder(DataModel dataItem, int currentPosition){ this.mDataItem=dataItem; //Handle selection state in object View. if(currentPosition == mSelectedItemPosition){ llView.setBackgroundColor(Color.ParseColor(SELCTED_COLOR); }else{ llView.setBackgroundColor(Color.ParseColor(DEFAULT_COLOR); } //other View binding logics like setting text , loading image etc. textView.setText(mDataItem); } } }
If you need to maintain only the selected state of an element, I highly recommend using the notifyDataSetChanged () method of the Adapter class, since RecyclerView provides much more flexibility for these cases.