Few projects ago I started using RecycleView. First I was impressed how extensible it was (animations, view types, layout manager, etc.). You could write ViewHolder that was representing particular ViewModel, pass it to your adapter and it would render it and it would animate changes/additions/deletions. Nice! But it required you to track where particular ViewModel was in your collection.

Discovery

So then one day, when I was browsing new additions in support library I discovered SortedList.

A Sorted list implementation that can keep items in order and also notify for changes in the list such that it can be bound to a RecyclerView.Adapter. It keeps items ordered using the compare(Object, Object) method and uses binary search to retrieve items. If the sorting criteria of your items may change, make sure you call appropriate methods while editing them to avoid data inconsistencies. You can control the order of items and change notifications via the SortedList.Callback parameter.

It is collection created by Support Android Team. It handles updates, addition and deletion of objects in collection. They are stored in binary tree structure, so access time are quite inexpensive O(log(n)). Core of this collection is SortedList.Callback.

Callbacks methods can be divided into two parts:

Equality and ordering

boolean areContentsTheSame (T2 oldItem, T2 newItem) boolean areItemsTheSame (T2 item1, T2 item2) int compare (T2 o1, T2 o2)

Above methods will decide which of an outcome callback (described later) will be called. First two methods: areContentsTheSame, areItemsTheSame are basically hashCode and equals implementation. Those are used to determine if object was added or updated and are called after compare method returns “0” in comparison step.

So lets focus on that. I have to admit that compare method is core of SortedList brilliant functionality. SortedList is binary tree structure collection which uses compare to determine ordering. Each comparison returns integer value that tells SortedList which branch of binary tree it should fall through. If compare returns “0” at some point we have matching object and collection moves to checking of its contents. There are three scenarios here worth exploring: addition(update)/deletion/moving.

In first scenario collection first searches for object that we want to add, by using compare. If none of checks return “0” we have to add object as leaf on the last branch that we performed comparison on. Otherwise we swap found object with new one. In this scenario we also perform areContentsTheSame, areItemsTheSame to fire right outcome callback.

In second scenario we just search for matching object by using compare and remove if we have match.

Third scenario requires SortedList to perform two binary searches. First to find edited element and then to move it into new place (this one is a little bit tricky at first sight, but more on that subject in next post).

Outcome callbacks

void onChanged (int position, int count) void onInserted (int position, int count) void onMoved (int fromPosition, int toPosition) void onRemoved (int position, int count)

So after SortedList figures out what happened in data set it fires callback informing about change. There are four methods: onChanged, onInserted, onMoved, onRemoved with appropriate arguments.

Additional benefit is that we have one place to call notify*** functions from adapter, which will trigger animations if we have them.

What it has to do with RecyclerView

So every add/update/move action has O(log(n)) complexity. You would think that it also applies to reading. Yes, but there is little asterisk to it. Above is true if you want to read particular object in collection, because SortedList has to find it with binary search. But if you want to display already ordered items (as RecyclerView would do), you access object in constant time! This is due fact that objects inside SortedList are stored in array. And all changes made on SortedList just shift them within bounds of this array.

So what?

So by now we know that there is this complicated collection that uses binary search to store objects. How can we use that to our advantage? Well, we can get rid of indexes all together!

In MVP architecture we want Presentation layer to have as little knowledge about View layer as possible. Imagine that Presenter would just pass ViewModels to View layer telling it what to do with it (add/remove/update/move) and that is it. It is View layer responsibility to render given object in right place based on its type. This way we gain following advantages:

Indexes disappear — presenter no longer tells view where to put data on screen, Ordering becomes declarative — we implement ordering in compare method, Interactive collection — instead of just storing objects it also tells us how they changed.

What’s next?

Enough theory, next time we will look at some code!

Continue to part 2