The Setup

With the database preloaded with 1000 users with random data, the setup for comparing the two implementations is as follows:

Perform a fling gesture and wait for the list to settle Do this 5 times Compute the duration of all onBindViewHolder method calls and log it Compare both the distribution, average, and standard deviation

This isn’t the strictest test setup as there’s bound to be some variation in my flings. I could have automated the flings, but with enough manual flings it’s going to average out… at least that’s what I keep telling myself.

Results

So here’s the average and standard deviation for both implementations:

Cursor — Average: 0.6ms, Standard Deviation: 0.33ms

Paging — Average: 0.43ms, Standard Deviation: 0.26ms

Well that’s promising. On average the Paging list adapter is about 30% faster with a marginally tighter deviation around the mean.

Let’s have a look at the distributions as I think that paints a better picture.

There’s a nice peak around 0.2ms for the paging list adapter, although above 1.5ms the paging implementation does demonstrate more frequent long loading times. It’s pretty minor as those results only makeup about 3% of the calls to onBindViewHolder.

Conclusions

Digging into the source of the generated UsersDao implementation it uses a LimitOffsetDataSource under the hood. Further investigation shows that it batches up a list of user objects given the PagedList.Config settings. My best guess is that the batched query and conversion to a list of objects results in faster loading.

Here’s a snippet of the decompiled LimitOffsetDataSource class file

public List<T> loadRange(int startPosition, int loadCount) {

RoomSQLiteQuery sqLiteQuery = RoomSQLiteQuery.acquire(

this.mLimitOffsetQuery,

this.mSourceQuery.getArgCount() + 2); sqLiteQuery.copyArgumentsFrom(this.mSourceQuery);

sqLiteQuery.bindLong(sqLiteQuery.getArgCount() - 1, (long)loadCount);

sqLiteQuery.bindLong(sqLiteQuery.getArgCount(), (long)startPosition); Cursor cursor = this.mDb.query(sqLiteQuery);



List var5;

try {

var5 = this.convertRows(cursor);

} finally {

cursor.close();

sqLiteQuery.release();

}



return var5;

}

Overall I like the flexibility of the library and I think the performance gains will be well received. The native thread management and configuration options allow some additional tuning depending on the data structures used. I didn’t touch on DiffUtil or DiffCallback, but expect additional performance gains from that depending on your data sources.

Here’s a link to the source if you’re interested.