Как использовать ContentObserver с RecyclerView?

С ListView у нас был хороший собственный шаблон для сопоставления некоторых данных из db в список:

DBContentProviderCursorLoaderCursorAdapterListView

Этот подход был хорош с точки зрения разделения данных, производительности и автоматических обновлений данных. Но этот шаблон не подходит для нового RecyclerView. Существуют некоторые подходы к воспроизведению старого поведения:

Использование recyclerview с базой данных

Но есть проблема с использованием старого стиля notifyDataSetChanged с RecyclerView. Он не может использовать функции ItemAnimator, он теряет положение прокрутки, и он просто неэффективен.

Итак, как мы можем извлечь выгоду из мелкомасштабных уведомлений об изменениях при использовании DB, завернутых в ContentProvider? Cursor является статическим, и для получения новых данных из него нам нужно получить новый Cursor. Таким образом, нам кажется, что нам понадобится пользовательский промежуточный уровень данных, который объединит данные из Cursors и выведет List объектов в RecyclerView.Adapter. Кроме того, нам придется вручную сопоставлять события ContentObserver onChange() с уведомлениями RecyclerView. Это также означает, что нам придется избавиться от CursorLoader. Это невероятная работа для такой основной задачи.

Есть ли лучшее решение?

Ответ 1

Вы можете использовать класс DiffUtils для вычисления различий между старым и новым курсором.

При использовании его вам просто нужно реализовать два метода:

  • areItemsTheSame(), чтобы узнать, представляют ли два элемента один и тот же логический элемент (даже если содержимое отличается). Обычно вы должны основывать ответ на поле идентификации вашего элемента;
  • areContentsTheSame(), чтобы знать, имеют ли два элемента, представляющие один и тот же логический элемент, немодифицированный контент.

После вычисления различий вы можете просто применить его к вашему адаптеру, и он автоматически вызовет notifyItemChanged(), notifyItemInserted() или notifyItemRemoved().