У меня проблема с библиотекой DiffUtil.ItemCallback
, когда старое состояние элемента списка каким-то образом теряется и приводит к тому, что oldTask
принимает те же значения, что и newTask
.
Это происходит, когда я устанавливаю / снимаю флажок в моем ListAdapter и onChanged()
в моем наблюдателе LiveData вызывает функции DiffUtil.ItemCallback
. Как вы можете видеть внутри onBindViewHolder()
, это действие вызывает setCompleted()
, что сводит на нет значение isCompleted()
. Ожидаемое поведение для просроченной задачи (красного цвета) - окрашивание в белый цвет всякий раз, когда установлен флажок. Это связано с тем, что isOverdue()
может возвращать false только тогда, когда isCompleted()
возвращает true
.
onBindViewHolder ():
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
SubTask subTask = getItem(i);
Log.d(TAG, "onBindViewHolder: CALLED");
viewHolder.subTaskName.setText(subTask.getName());
Calendar dueDate = subTask.getDueDate();
viewHolder.dueDate.setText(context.getResources().getString(R.string.due_date, dueDate.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG, Locale.getDefault()), dueDate.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.getDefault()), dueDate.get(Calendar.DAY_OF_MONTH), dueDate.get(Calendar.YEAR)));
viewHolder.checkBox.setOnCheckedChangeListener(null);
//check of sub task if completed
if (subTask.isCompleted()) {
viewHolder.checkBox.setChecked(true);
} else {
viewHolder.checkBox.setChecked(false);
}
if (subTask.isOverdue()) {
viewHolder.card.setCardBackgroundColor(context.getColor(R.color.red));
viewHolder.subTaskName.setTextColor(context.getColor(R.color.colorAccent));
viewHolder.dueDate.setTextColor(context.getColor(R.color.colorAccent));
} else {
viewHolder.card.setCardBackgroundColor(context.getColor(R.color.colorAccent));
viewHolder.subTaskName.setTextAppearance(R.style.TextAppearance_AppCompat_Large);
viewHolder.dueDate.setTextColor(context.getColor(R.color.main_task_text_color));
}
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);
viewModel = ViewModelProviders.of((FragmentActivity) context).get(ViewSubTasksForMainTaskViewModel.class);
if (isChecked) {
//if overdue, change card to white
subTask.setCompleted(true);
viewModel.updateSubTask(subTask);
} else {
//if overdue, set color back to red
subTask.setCompleted(false);
viewModel.updateSubTask(subTask);
}
}
});
}
Однако, когда areContentsTheSame()
пытается сравнить значения в старом и новом списках, иногда возвращает true
, когда этого не следует делать, так как isCompleted()
должен возвращать разные значения для старого и нового элементов списка. Кажется, что старое состояние элемента списка каким-то образом потеряно. Это приводит к тому, что элементы списка отображаются неправильно, поскольку onBindViewHolder()
не вызывается. Вот GIF , который показывает, как приложение ведет себя. Как видите, элементы списка имеют красный цвет, даже если они отмечены, а элементы списка - белые, даже если они не отмечены. Вы также можете видеть, что некоторые элементы списка отображаются правильно, но не все из них.
DiffCallback:
public class SubTaskDiffCallback {
private static final String TAG = "SubTaskDiffCallback";
static public DiffUtil.ItemCallback<SubTask> getSubTaskDiffCallback() {
return new DiffUtil.ItemCallback<SubTask>() {
@Override
public boolean areItemsTheSame(@NonNull SubTask oldTask, @NonNull SubTask newTask) {
Log.d(TAG, "areItemsTheSame: " + oldTask.getName() + " " + newTask.getName() + " " + Boolean.toString(oldTask.getId() == newTask.getId()));
return oldTask.getId() == newTask.getId();
}
@Override
public boolean areContentsTheSame(@NonNull SubTask oldTask, @NonNull SubTask newTask) {
Log.d(TAG, "areContentsTheSame: oldTask " + oldTask.toString());
Log.d(TAG, "areContentsTheSame: newTask " + newTask.toString());
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;
}
@Nullable
@Override
public Object getChangePayload(@NonNull SubTask oldTask, @NonNull SubTask newTask) {
if (oldTask.isCompleted() != newTask.isCompleted()) {
Log.d(TAG, "getChangePayload = false");
return Boolean.FALSE;
} else {
return null;
}
}
};
}
}
Вот неполный журнал событий, связанных в GIF-файле. выше:
2020-02-02 15:45:21.536 8226-8226/com.johnsorhannus.divideandconquer D/ViewSTForMTAdapter: onCheckedChanged: called for subTask Wash car isChecked = true
2020-02-02 15:45:21.555 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:21.555 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:21.556 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:21.556 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:21.556 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:21.556 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:21.557 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:21.557 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:21.557 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:21.557 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = true, completed = false]
2020-02-02 15:45:21.558 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = true, completed = false]
2020-02-02 15:45:21.558 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:21.558 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = true, completed = false]
2020-02-02 15:45:21.558 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = true, completed = false]
2020-02-02 15:45:21.558 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:22.979 8226-8226/com.johnsorhannus.divideandconquer D/ViewSTForMTAdapter: onCheckedChanged: called for subTask Read OS book isChecked = true
2020-02-02 15:45:22.999 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:22.999 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:22.999 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:22.999 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:22.999 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:22.999 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:23.000 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:23.001 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:23.001 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:23.002 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = true, completed = false]
2020-02-02 15:45:23.002 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = false, completed = true]
2020-02-02 15:45:23.002 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = false
2020-02-02 15:45:23.003 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = true, completed = false]
2020-02-02 15:45:23.004 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = true, completed = false]
2020-02-02 15:45:23.004 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:23.004 8226-8226/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: getChangePayload = false
2020-02-02 15:45:23.014 8226-8226/com.johnsorhannus.divideandconquer D/ViewSTForMTAdapter: onBindViewHolder: CALLED
2020-02-02 15:45:24.275 8226-8226/com.johnsorhannus.divideandconquer D/ViewSTForMTAdapter: onCheckedChanged: called for subTask Read database book isChecked = true
2020-02-02 15:45:24.294 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:24.294 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:24.294 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:24.294 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:24.294 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:24.294 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:24.295 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:24.295 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:24.295 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:24.296 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = false, completed = true]
2020-02-02 15:45:24.296 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = false, completed = true]
2020-02-02 15:45:24.296 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:24.296 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = true, completed = false]
2020-02-02 15:45:24.297 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = false, completed = true]
2020-02-02 15:45:24.297 8226-11254/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = false
2020-02-02 15:45:24.297 8226-8226/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: getChangePayload = false
2020-02-02 15:45:24.308 8226-8226/com.johnsorhannus.divideandconquer D/ViewSTForMTAdapter: onBindViewHolder: CALLED
2020-02-02 15:45:26.590 8226-8226/com.johnsorhannus.divideandconquer D/ViewSTForMTAdapter: onCheckedChanged: called for subTask Read database book isChecked = false
2020-02-02 15:45:26.608 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:26.608 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:26.608 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:26.608 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read database book Read database book true
2020-02-02 15:45:26.608 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Read OS book Read OS book true
2020-02-02 15:45:26.608 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areItemsTheSame: Wash car Wash car true
2020-02-02 15:45:26.609 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:26.609 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Wash car, dueDate = Mar 17, 2019, overdue = false, completed = true]
2020-02-02 15:45:26.609 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:26.610 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = false, completed = true]
2020-02-02 15:45:26.610 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read OS book, dueDate = Mar 20, 2019, overdue = false, completed = true]
2020-02-02 15:45:26.610 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
2020-02-02 15:45:26.611 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: oldTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = true, completed = false]
2020-02-02 15:45:26.611 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame: newTask SubTask[name = Read database book, dueDate = Mar 23, 2019, overdue = true, completed = false]
2020-02-02 15:45:26.611 8226-11255/com.johnsorhannus.divideandconquer D/SubTaskDiffCallback: areContentsTheSame = true
Я точно знаю, что setCompleted()
изменил значение isCompleted()
, потому что при выходе и повторном входе в действие, правильно отображает .