Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RecyclerView and DiffUtil - A Concurrency Nightmare

The documentation for DiffUtil suggests generating the DiffUtil.DiffResult on a background thread because of potential long calculation times. This seems like a bad idea to me, because that thread could be operating on stale data in a situation like the following (assuming list access is thread safe):

  1. Add data to list and notify adapter
  2. Need to replace list with newList which would have a diff of some additions and some removals
  3. Call DiffUtil.calculateDiff in the background and get the DiffResult for list and newList, and post a message to the main thread that will use newList and call DiffResult.dispatchUpdatesTo
  4. Before that message is handled, the user takes an action on the main thread that causes mutations to list
  5. The message is handled, newList is set to be the new data source and DiffResult.dispatchUpdatesTo is run causing an inconsistent view of the underlying data + a loss of any mutations since the DiffResults were calculated

Well that's no good, so let's change starting from step 3:

  1. Set newList as the new data source, call DiffUtil.calculateDiff in the background and get the DiffResult for list and newList, and post a message to the main thread that will call DiffResult.dispatchUpdatesTo
  2. Before that message is handled, the user takes an action on the main thread that causes mutations to newList, and notifies adapter, causing an inconsistent view of data because DiffResult.dispatchUpdatesTo hasn't been called yet

There are more variations on this, but none are good. It seems like the only way to reliably use DiffUtil with a large dataset and changeset is to either disable or queue all updates until DiffResult.dispatchUpdatesTo is called.

Am I missing something that would make the above false?

like image 710
Eliezer Avatar asked Oct 27 '16 17:10

Eliezer


1 Answers

I ended up stacking updates to manage user interaction during DiffUtil calculations and still accessing dataset in Main Thread only.

I wrote it there: https://geoffreymetais.github.io/code/diffutil-threading/

like image 175
Geoffrey Avatar answered Oct 22 '22 09:10

Geoffrey