0

The google sample for a TODO app using MVVM, databinding, LiveData and notifyDataSetChanged(). I would like to replace this with DiffUtil. The sample reloads the data in the fragments onResume function.

TasksFragment.java

Reloads the whole dataSet in onResume function.

@Override
public void onResume() {
    super.onResume();
    mTasksViewModel.start();
}

tasks_frag.xml

<ListView
    android:id="@+id/tasks_list"
    app:items="@{viewmodel.items}"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

Adapter

public class TasksAdapter extends BaseAdapter {
    private final TasksViewModel mTasksViewModel;
    private List<Task> mTasks;

    private void setList(List<Task> tasks) {
        mTasks = tasks;
        notifyDataSetChanged();
    }
}

TasksListBindings.java

public class TasksListBindings {

    @SuppressWarnings("unchecked")
    @BindingAdapter("app:items")
    public static void setItems(ListView listView, List<Task> items) {
        TasksAdapter adapter = (TasksAdapter) listView.getAdapter();
        if (adapter != null)
        {
            adapter.setData(items);
        }
    }
}

I already implemented the DiffUtil as replacement of notifyDataSetChanged like this.

protected void setList(List<Item> tasks) {
    Log.d("customeee", "mTasks setList");
    final ItemsDiffCallback diffCallback = new ItemsDiffCallback(this.mTasks, tasks);
    final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(diffCallback);

    diffResult.dispatchUpdatesTo(this);
    this.mTasks.clear();
    this.mTasks.addAll(tasks);

}

But what happens is no matter what I do the areContentsTheSame function is always returning true. If I force a false, the update is working just fine.

@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
    final Item oldItem = mOldList.get(oldItemPosition);
    final Item newItem = mNewList.get(newItemPosition);

    Log.d("customeee", oldItem.getNote() + " newItem: "+newItem.getNote());
    Log.d("customeee", "New == old? "+mOldList.equals(mNewList));

    return oldItem.getNote().equals(newItem.getNote());
}

The oldItem.getNote() and newItem.getNote() are both returning the new value. I think this has something todo with the reference if the list object as oldList.equals(newList).

S. Gissel
  • 1,788
  • 2
  • 15
  • 32
  • 1
    You can see this example here https://github.com/MMRBD/Note-MVVM-Room-LiveData – Moklesur Rahman Oct 10 '19 at 19:27
  • @MMR your reference helped me a lot. Below I posted an answer that finally helped me to fix this issue. – S. Gissel Oct 15 '19 at 13:38
  • 1
    i am also facing the same issue recently. Although your adapter list is a new ArrayList<> but when you do add() or addAll() you are basically adding same object to a new list. So if you modify the list item from adapter list or viewmodel, changes will be reflected in both list as both list contains same object. What I did was passed a HashMap map to my adapter. position tells which position item has changed and the Object has what has changed and used that inside areContentsTheSame(). Couldn't come up with a clean way so far. – Shikhar Deep Nov 20 '20 at 15:36
  • 1
    Full approach here: https://stackoverflow.com/questions/57876118/diffutil-itemcallback-arecontentsthesame-always-returns-true-after-updating-an/64932645#64932645 – Shikhar Deep Nov 20 '20 at 16:08

1 Answers1

0

Solution:

Instead of using the DiffUtil directly Google came up with a new solution - the AsyncListDiffer. This small code sample from the class reference brought the answer.

Also I was missing something. In the Google sample they create a new object to save to the repository. Which is needed:

item = new Item(title.getValue(), description.getValue(), mTaskId, mItemCompleted);
updateItem(item);

What I did is to just update the existing object with the new values expected to change:

this.item.getValue().setFavorite(favorite.getValue());
this.item.getValue().setNote(note.getValue());
updateTask(item.getValue());

Following the implementation guide for AsyncListDiffer and the Google sample app helped me to solve this issue.

S. Gissel
  • 1,788
  • 2
  • 15
  • 32