Test-Driven Android: Testing Multiple Cursor Loaders for One Activity/Fragment

I’ve found some favorite resources on writing Android apps. One of my favorites is Virgil Dobjanschi’s Google I/O Talk on Android apps as REST clients. This talk is relevant to every business-related app I’ve ever built, because most apps, on a general level, solve a lot of the same problems. Fetching data from an API and displaying it on the app is one of those problems. How many apps that I’ve built have demanded this functionality? All of them.

Virgil describes a couple of different levels of advancement for fetching and displaying data in an Android app. Lately, I have favored the most advanced one: making a call with a service, sticking the results in a database, and accessing them with a content provider and cursor loader to display on the UI.

Lots of tutorials will help you implement this pattern…on the simplest level. But what happens when, say, you have multiple tables, and you want to register updates for all of them on the same UI? If your LoaderCallbacks implementer is pulling from multiple databases, then your onLoadFinished() method has to distinguish between different CursorLoaders for each of your databases. And if the generic type for any of the CursorLoaders is the same, then you need to distinguish between them from within one onLoadFinished() method—because you can’t implement that method twice with the same signature.

Everyone on StackOverflow describes one of two solutions.

1) Implement two separate onLoadFinished methods and change one of the Loader’s generic types to not-a-cursor for the express purpose of loading them both in one activity/fragment. This works by adding a layer of indirection that can make the code confusing for developers who are unfamiliar with the pattern.

2) rely on the loader ID, which makes total sense, and works for the implementation code. The problem comes, as it frequently does with mobile development, when you try to unit test this approach. When we call onCreateLoader() from a test, the loader id does not get set. 

Seriously, take this code:

Print the loader.getId() for the loader that gets returned when you call onCreateLoader() in your tests. It will be zero in both cases, despite the fact that we expect the ids to be 1 and 2.

So what to do? I spelunked through the CursorLoader code a little and found a method that sets the id on the CursorLoader: registerListener(int id, OnLoadCompleteListener<Cursor> listener).

So when we add this call to our onCreateLoader() method, we get this:

and that sets the loader id!

So now you can have a clean switch case in your onLoadFinished() method:

If you have been banging your head against this (as I did at first), please pay it forward and share this post with another Android dev who might like to know.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s