Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use ContentObserver with RecyclerView?

With ListView we have had a good native pattern to map some data from db to list:

DB -> ContentProvider -> CursorLoader -> CursorAdapter -> ListView

This approach was good in terms of data layer separation, performance and automatic data updates. But this pattern doesn't really fit new RecyclerView. There are some approaches to mimic old behavior:

Using the recyclerview with a database

But there is a problem with using old style notifyDataSetChanged with RecyclerView. It can't use ItemAnimator features, it loses scrolling position, and it's just ineffective.

So, how we can benefit from finegraned change notifications while using DB wrapped in ContentProvider? Cursor is static, and to get new data from it we need to get new Cursor. So, it seems that we will need an custom intermediate data layer, which will merge data from Cursors and expose the List of entities to RecyclerView.Adapter. Also, we will have to manually map ContentObserver onChange() events to RecyclerView notifications. This also means that we will have to get rid of CursorLoader. That is an incredible amount of work for such basic task.

Is there any better solution?

like image 527
rudzha Avatar asked Apr 24 '15 10:04

rudzha


1 Answers

You can use the DiffUtils class to compute the differences between the old and new cursor.

When using it you just need to implement two methods :

  • areItemsTheSame() to know if two items represent the same logical item (even if the content is different). Usually you would base the answer on an identifying field of your item;
  • areContentsTheSame() to know if two items representing the same logical item have unmodified content.

Once the differences are computed, you can then just apply it to your adapter and it will automatically call the notifyItemChanged(), notifyItemInserted() or notifyItemRemoved() accodingly.

like image 86
XGouchet Avatar answered Oct 04 '22 06:10

XGouchet