ListAdapter items rendered incorrectly when LiveData onChanged() method is called. Possible issue with DiffUtil areContentsTheSame()?

John S. :

I'm currently creating an Android app that helps you complete tasks. I'm using LiveData along with a ListAdapter that lists all the different tasks in a Fragment and DiffUtil to test for changes in the ListAdapter. Before I explain my problem: here is some relevant code:

SubTaskFragment.java:

public class SubTaskFragment extends Fragment {
private RecyclerView recyclerView;

private SubTaskAdapter adapter;
private SubTaskViewModel viewModel;

private static final String TAG = "SubTaskFragment";

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment and setup recycler view
    View rootView = inflater.inflate(R.layout.fragment_sub_task, container, false);
    recyclerView = (RecyclerView) rootView.findViewById(R.id.sub_task_recycler_view);
    recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));

    //set adapter
    adapter = new SubTaskAdapter(getContext());
    recyclerView.setAdapter(adapter);

    viewModel = ViewModelProviders.of(this).get(SubTaskViewModel.class);
    viewModel.getSubTasks().observe(getViewLifecycleOwner(), new Observer<List<SubTask>>() {
        @Override
        public void onChanged(@Nullable List<SubTask> subTasks) {
            //Update RecyclerView
            Log.d(TAG, "onChanged: subTasks length = " + subTasks.size());
            adapter.submitList(subTasks);
        }
    });

SubTaskAdapter.java

public class SubTaskAdapter extends ListAdapter<SubTask, SubTaskAdapter.ViewHolder> {
private static final String TAG = "SubTaskAdapter";

private SubTaskViewModel subTaskViewModel;

public SubTaskAdapter(Context context) {
    super(DIFF_CALLBACK);
    this.context = context;
}

private static final DiffUtil.ItemCallback<SubTask> DIFF_CALLBACK = new DiffUtil.ItemCallback<SubTask>() {
    @Override
    public boolean areItemsTheSame(@NonNull SubTask oldTask, @NonNull SubTask newTask) {
        Log.d(TAG, "areItemsTheSame: oldTask name: " + oldTask.getName() + " id: " + oldTask.getId() + " ### newTask name: " + newTask.getName() + " id: " + newTask.getId());
        return oldTask.getId() == newTask.getId();
    }

    @Override
    public boolean areContentsTheSame(@NonNull SubTask oldTask, @NonNull SubTask newTask) {
        Log.d(TAG, "areContentsTheSame: oldTask name: " + oldTask.getName() + " ### newTask name: " + newTask.getName());
        boolean contentsSame = oldTask.getName().equals(newTask.getName()) &&
                oldTask.getDueDate().equals(newTask.getDueDate()) &&
                oldTask.isCompleted() == newTask.isCompleted() &&
                oldTask.getMainTaskId() == (newTask.getMainTaskId());
        Log.d(TAG, "areContentsTheSame: = " + contentsSame);
        return contentsSame;
    }
};

@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
    SubTask subTask = getItem(i);
    Log.d(TAG, "onBindViewHolder: pos: " + i + " name: " + subTask.getName() + " Is overdue: " + subTask.isOverdue());

    Log.d(TAG, "onBindViewHolder: " + subTask.getName() + " isOverdue = " + subTask.isOverdue());
    //SET BACKGROUND COLOR OF LIST ITEM
    if (subTask.isOverdue()) {
        viewHolder.card.setCardBackgroundColor(context.getResources().getColor(R.color.red));
        viewHolder.subTaskName.setTextColor(context.getResources().getColor(R.color.colorAccent));
        viewHolder.mainTaskName.setTextColor(context.getResources().getColor(R.color.colorAccent));
    }

    if (subTask.isCompleted()) {
        viewHolder.checkBox.setChecked(true);
        Log.d(TAG, "onBindViewHolder: " + subTask.getName() + " set to checked");
    } else {
        viewHolder.checkBox.setChecked(false);
        Log.d(TAG, "onBindViewHolder: " + subTask.getName() + " set to unchecked");
    }

    viewHolder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() 
    {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            Log.d(TAG, "onCheckedChanged: called for subTask " + subTask.getName() + " isChecked = " + isChecked);
            subTaskViewModel = ViewModelProviders.of((FragmentActivity) context).get(SubTaskViewModel.class);
            if (isChecked) {
                subTask.setCompleted(true);
                subTaskViewModel.updateSubTask(subTask);
            } else {
                subTask.setCompleted(false);
                subTaskViewModel.updateSubTask(subTask);
            }
        }
    });

The first problem I am experiencing is that as a list item's checkbox is checked by a user, the list item turns gray like so. This is not the expected behavior, as the color of the list item is not supposed to change as its being checked. This does not happen when it is unchecked.

Here's the log of this action:

2020-01-19 15:24:47.572 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onCheckedChanged: called for subTask Test 1 isChecked = true
2020-01-19 15:24:47.575 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskViewModel: updateSubTask: CALLED for Test 1 isCompleted = true isOverdue = false
2020-01-19 15:24:47.602 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskFragment: onChanged: subTasks length = 5
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read database book id: 1 ### newTask name: Read database book id: 1
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read database book id: 1 ### newTask name: Read database book id: 1
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Wash car ### newTask name: Wash car
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read OS book ### newTask name: Read OS book
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read database book ### newTask name: Read database book
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 1 ### newTask name: Test 1
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = false
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 2 ### newTask name: Test 2
2020-01-19 15:24:47.603 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:47.652 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: pos: 3 name: Test 1 Is overdue: false
2020-01-19 15:24:47.652 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: Test 1 isOverdue = false
2020-01-19 15:24:47.655 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: Test 1 set to checked
2020-01-19 15:24:50.633 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onCheckedChanged: called for subTask Test 1 isChecked = false
2020-01-19 15:24:50.633 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskViewModel: updateSubTask: CALLED for Test 1 isCompleted = false isOverdue = false
2020-01-19 15:24:50.664 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskFragment: onChanged: subTasks length = 5
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read database book id: 1 ### newTask name: Read database book id: 1
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read database book id: 1 ### newTask name: Read database book id: 1
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:24:50.664 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Wash car ### newTask name: Wash car
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read OS book ### newTask name: Read OS book
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read database book ### newTask name: Read database book
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 1 ### newTask name: Test 1
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 2 ### newTask name: Test 2
2020-01-19 15:24:50.665 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true

The next, and possibly related, problem I'm experiencing is whenever a list item is "overdue" (tasks in red) and I check it off, other items in the ListAdapter turn red when I hit it's corresponding checkbox. This is not the way it is supposed to function. These list items are supposed to be white since those tasks are not overdue. It eventually turns back to white again when I check/uncheck it a second time.

The app functions properly when an overdue task is checked. It gets removed from the screen because an overdue task that is checked is no longer returned by my SQL SELECT statement.

Here is the log for when I check/uncheck a non-overdue list item twice (3rd gif). One important thing to note here is that when Test 1 is checked, areContentsTheSame() correctly returns false when the list item is checked since isCompleted has been set from true to false. However, areContentsTheSame() incorrectly returns true when it is unchecked even though isCompleted has been set from true to false. Also, even though isOverdue is false, the list item all of a sudden turns to red:

2020-01-19 15:28:52.071 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onCheckedChanged: called for subTask Test 1 isChecked = true
2020-01-19 15:28:52.072 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskViewModel: updateSubTask: CALLED for Test 1 isCompleted = true isOverdue = false
2020-01-19 15:28:52.104 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskFragment: onChanged: subTasks length = 4
2020-01-19 15:28:52.104 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:52.104 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:52.104 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:52.104 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:52.104 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:52.104 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Wash car ### newTask name: Wash car
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read OS book ### newTask name: Read OS book
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 1 ### newTask name: Test 1
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = false
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 2 ### newTask name: Test 2
2020-01-19 15:28:52.105 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:52.136 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: pos: 2 name: Test 1 Is overdue: false
2020-01-19 15:28:52.137 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: Test 1 isOverdue = false
2020-01-19 15:28:52.137 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: Test 1 set to checked
2020-01-19 15:28:54.080 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onCheckedChanged: called for subTask Test 1 isChecked = false
2020-01-19 15:28:54.081 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskViewModel: updateSubTask: CALLED for Test 1 isCompleted = false isOverdue = false
2020-01-19 15:28:54.102 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskFragment: onChanged: subTasks length = 4
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Wash car ### newTask name: Wash car
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read OS book ### newTask name: Read OS book
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 1 ### newTask name: Test 1
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 2 ### newTask name: Test 2
2020-01-19 15:28:54.103 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:58.480 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onCheckedChanged: called for subTask Test 1 isChecked = true
2020-01-19 15:28:58.481 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskViewModel: updateSubTask: CALLED for Test 1 isCompleted = true isOverdue = false
2020-01-19 15:28:58.498 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskFragment: onChanged: subTasks length = 4
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Wash car ### newTask name: Wash car
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read OS book ### newTask name: Read OS book
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 1 ### newTask name: Test 1
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = false
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 2 ### newTask name: Test 2
2020-01-19 15:28:58.499 27375-27504/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:58.529 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: pos: 2 name: Test 1 Is overdue: false
2020-01-19 15:28:58.529 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: Test 1 isOverdue = false
2020-01-19 15:28:58.529 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onBindViewHolder: Test 1 set to checked
2020-01-19 15:28:59.922 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskAdapter: onCheckedChanged: called for subTask Test 1 isChecked = false
2020-01-19 15:28:59.922 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskViewModel: updateSubTask: CALLED for Test 1 isCompleted = false isOverdue = false
2020-01-19 15:28:59.941 27375-27375/com.johnsorhannus.divideandconquer D/SubTaskFragment: onChanged: subTasks length = 4
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 2 id: 5 ### newTask name: Test 2 id: 5
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Test 1 id: 4 ### newTask name: Test 1 id: 4
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Read OS book id: 2 ### newTask name: Read OS book id: 2
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areItemsTheSame: oldTask name: Wash car id: 3 ### newTask name: Wash car id: 3
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Wash car ### newTask name: Wash car
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Read OS book ### newTask name: Read OS book
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 1 ### newTask name: Test 1
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: oldTask name: Test 2 ### newTask name: Test 2
2020-01-19 15:28:59.941 27375-27409/com.johnsorhannus.divideandconquer D/SubTaskAdapter: areContentsTheSame: = true

One other thing that I am noticing is that areItemsTheSame() is called twice for every item on the list while areContentsTheSame() is called only once for each list item. This doesn't seem to be normal behavior, so this may be contributing to the problem somehow. Any thoughts on if the two issues are related and how to fix them?

Ben P. :

You've got two issues here. The first (the gray highlight) is happening because of the built-in default animations of RecyclerView. When you check the box, the RecyclerView creates a new ViewHolder and does a crossfade. See this question/answer for more information on how to solve it: RecyclerView.ItemDecoration doesn't update after item is removed from RecyclerView.Adapter

The second (the red background) is an error in your onBindViewHolder() method that prevents views from being recycled correctly:

if (subTask.isOverdue()) {
    viewHolder.card.setCardBackgroundColor(context.getResources().getColor(R.color.red));
    viewHolder.subTaskName.setTextColor(context.getResources().getColor(R.color.colorAccent));
    viewHolder.mainTaskName.setTextColor(context.getResources().getColor(R.color.colorAccent));
}

Every if statement like this needs an else case to set the views back to the normal colors. Without such an else, your red view is recycled to another position and nothing changes the color back.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=356591&siteId=1