DiffUtil — performant one way data flow with RxJava and Kotlin

This is a tutorial on how we can leverage DiffUtil, RxJava, andKotlin for performant unidirectional data flow when binding data to a RecyclerView.

We want to achieve three things

  1. Access to the previously emitted list that populates the RecyclerView within the Rx stream to allow us to use DiffUtil
  2. DiffUtil.calculateDiff is expensive, so this should be performed on a background thread.
  3. Clean code!

Accessing the previously emitted list on the stream

At first, I tried to utilize the .scan() operator, which allows you to apply a Func2 to an emission and its previous emission. Unfortunately, this was a non-starter because it requires you to return the same type as the emissions. I wanted to emit a Pair(oldData, newData) that I could then run calculateDiff() on.

With Kotlin’s extension functions and a little help, the aptly named .scanMap() operator was born.

Now, your stream can look like:

recyclerViewDataSet.asObservable() //hot stream of RV's data (list)
.observeOn(background)
.scanMap(emptyList(), { old, new -> Pair(old, new) })
.map { DiffUtil.calculateDiff( /** DiffUtil.callback */ ) }
.observeOn(main)
.subscribe { it.dispatchUpdatesTo(this) }

Go forth, and diff.