-1

I use onLongClickListener to items in RecyclerView status selected/unselected, and change item background color. The selection works fine, but some additional items down the list change colour too (although their state remains 'unselected'). My suspicion is that the problem is due to the viewholder being reused, but I don't know how to fix that. I followed this to implement multiple selection, which I absolutely need in the app.

public class TasksPagedAdapter extends PagedListAdapter<Task, TaskViewHolder> {

private static DiffUtil.ItemCallback<Task> DIFF_CALLBACK = new DiffUtil.ItemCallback<Task>() {
    @Override
    public boolean areItemsTheSame(@NonNull Task task, @NonNull Task t1) {

        return task.getId() == t1.getId();
    }

    @Override
    public boolean areContentsTheSame(@NonNull Task task, @NonNull Task t1) {
        return task.equals(t1);
    }
};

private ItemClickListener itemClickListener;

protected TasksPagedAdapter(ItemClickListener itemClickListener) {
    super(DIFF_CALLBACK);

    setHasStableIds(true);
    this.itemClickListener = itemClickListener;
}

@NonNull
@Override
public TaskViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int position) {

    View itemRootView = LayoutInflater
            .from(parent.getContext())
            .inflate(R.layout.item_tarea, parent, false);

    return new TaskViewHolder(itemRootView);
}

@Override
public void onBindViewHolder(@NonNull TaskViewHolder taskViewHolder, int position) {

    Task taskItem = getItem(position);

    int importancia = taskItem.getImportancia();
    switch (importancia) {
        case 0:
            taskViewHolder.iv_importancia.setImageResource(R.drawable.icon_importancia_0);
            break;
        case 1:
            taskViewHolder.iv_importancia.setImageResource(R.drawable.icon_importancia_1);
            break;
        case 2:
            taskViewHolder.iv_importancia.setImageResource(R.drawable.icon_importancia_2);
            break;
        case 3:
            taskViewHolder.iv_importancia.setImageResource(R.drawable.icon_importancia_3);
            break;
        case 4:
            taskViewHolder.iv_importancia.setImageResource(R.drawable.icon_importancia_4);
            break;
        default:
            taskViewHolder.iv_importancia.setImageResource(R.drawable.icon_importancia_0);
            break;
    }
    taskViewHolder.tv_asunto.setText(taskItem.getAsunto());
    taskViewHolder.tv_fecha_creacion.setText(taskItem.getFechaCreacion());
    taskViewHolder.item_container.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            itemClickListener.onItemClick(position);
        }
    });
    taskViewHolder.item_container.setOnLongClickListener(new View.OnLongClickListener() {
        @Override
        public boolean onLongClick(View v) {
            itemClickListener.onItemLongClick(position);

            taskItem.setSelected(!taskItem.isSelected());
            taskViewHolder.item_container.setBackgroundColor(taskItem.isSelected() ? Color.CYAN : Color.WHITE);

            return true;
        }
    });
}

public Task getListItem(int position) {
    return getItem(position);
}

public List<Integer> getSelectedTasks() {
    List<Integer> selectedTasksIds = new ArrayList<>();
    for (Task task : getCurrentList().snapshot()) {
        if (task.isSelected()) {
            selectedTasksIds.add(task.getId());
        }
    }
    return selectedTasksIds;
}

@Override
public long getItemId(int position) {
    return position;
}

}

Ajeet Yadav
  • 693
  • 1
  • 11
  • 31
Pedro Gonzalez
  • 1,429
  • 2
  • 19
  • 30
  • For Kotlin users, the following article might be useful [How to delete multiple records from Firestore using RecyclerView multi-selection?](https://medium.com/firebase-tips-tricks/how-to-delete-multiple-records-from-firestore-using-recyclerview-multi-selection-96108e4c6166). – Alex Mamo Jan 04 '21 at 17:12

3 Answers3

1

RecyclerView will reuse views to populate data.

Simply add this line taskViewHolder.item_container.setBackgroundColor(taskItem.isSelected() ? Color.CYAN : Color.WHITE); to onBindViewHolder to fix it (when you will scroll the right color will be set)

Yogi Bear
  • 603
  • 8
  • 22
0

Add this two methods in recyclerview adapter

 override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getItemViewType(position: Int): Int {
        return position
    }
Urvish Jani
  • 104
  • 1
  • 4
0

Override these methods in your Adapter class like this.

@Override
public long getItemId(int position) {
 return position;
}

@Override
public int getItemViewType(int position) {
 return position;
}
Ajeet Yadav
  • 693
  • 1
  • 11
  • 31