Roboelectric and ContentResolvers/ContentProviders

Setting up Roboelectric is dead simple. However, you may find that code like the one shown below doesn’t work:

//save using a task provider
Button saveButton = (Button) activity.findViewById(id.save_button);

//check that task was saved
ContentResolver resolver = activity.getContentResolver();
Cursor cursor = resolver.query(//...

assertTrue(cursor != null);

Nothing gets saved to the mock in-memory database. Your break points in the ContentProvider don’t get called.

What gives?

Register the ContentProvider

In Roboelectric, you need to manually register your content provider. The code below does the trick:

//instantiate the ContentProvider directly
TaskProvider taskProvider = new TaskProvider();

//register the ContentProvider
ShadowContentResolver.registerProvider(TaskProvider.AUTHORITY_NAME, taskProvider);

Thanks to Vardhan for the tip!

Unimplemented Methods

We’re almost there. The default mock in-memory database is pretty cool. For basic CRUD, it works pretty much like a real database except that everything is stored in memory.

However, you might find that queries don’t work. The reason is that as of 7/27/2013, Android API 16 (which is the default version Roboelectric uses) adds a new database method that Roboelectric hasn’t implemented yet.

The solution is to…implement the missing method yourself. You have two options:

  • Add the missing method directly to shadow class. (Requires that you work directly with the Roboelectric source code).
  • Create a custom class in your test and bind it at runtime to the framework. (I haven’t figure out how to do that yet in Roboelectric 2.)

The offending class is ShadowSqlLiteDatabase. Add this method and you should be good:

public Cursor rawQueryWithFactory (SQLiteDatabase.CursorFactory cursorFactory,
                                 String sql,
                                 String[] selectionArgs,
                                 String editTable,
                                 CancellationSignal cancellationSignal)
  return rawQueryWithFactory(cursorFactory,

Setup Roboelectric as a Submodule in Android Studio

Unit tests are awesome. In Android, the built-in unit tests are a kind of a drag because they require an emulator or a phone and APK deploys to the aforementioned device (in other words, they are slow). A popular alternative is Roboelectric. While it’s easy to add Roboelectric as a JAR or Maven dependency, it wasn’t so easy to add as a submodule.

“Why would you want Roboelectric as a submodule?” you ask.

Continue reading


Reminderer: Database Backend Redux

I spent last week rewriting the database backend and boy was it a convoluted mess.

First, I tried salvaging the existing framework but I couldn’t figure out what the heck it was doing. Then I tried an implementation using ThreadPools, but handling configuration changes meant re-inventing the wheel. (Re-inventing the wheels means that there’s a good chance the code might break in future Android versions.) Then I tried a version using DAOs. Unfortunately, the “Android way” (using Cursors) gives better performance, so I started again from scratch.

But what is the Android way? and what did I really want?

Continue reading


Reminderer Grammar Parser is Done!

I finished the grammar parser for Reminderer app. Yay!

I uploaded and made it available on the web thanks to Google App Engine. You can see it in action here:

(Unfortunately, you can’t embed it directly in WordPress, so you’ll have to click the link.)

You can say things like:

  • buy milk tomorrow 8pm
  • Pat’s birthday May 1 repeats yearly

Go ahead and take it for a test drive. Let me know if you find bugs!

Continue reading


Reminderer Redux

It’s been a while! I finally have some time to work on Reminderer (a TODO Android app).

Lessons Learned

I’ve spent the past couple of days commenting and refactoring the code, and boy do your programming skills improve in a year.

The current grammar parser has interfaces with only one implementation (unnecessary) and an inconsistent and obtuse design (maintenance nightmare). I built something quickly the first time around but now I’m paying the penalty because its taking me forever to re-understand it.

I keep remembering an article I read a few months ago by a well-respected programmer…the gist of it was that sometimes you need to put away “best practices” in order to “meet the deadline.” That’s true if you code and run, or if you don’t care about maintaining your code. Otherwise, you will have to spend some time on design, documentation, and refactoring with the goal of making the code intuitive. That way you or someone else in the future will have the shortest possible learning curve.

A New Vision for a UI

I’m a hug fan of Emac’s org-mode. For those of you who don’t know what Emacs is, it’s a 30+ year old editor (so yes, I’m a retro geek). Org-mode is a recent addition created by some Google employees that is like steroids to Emac’s outline mode.

What I love about org-mode is

  1. Dynamically create TODO items. It’s a blog post, now it’s a TODO item. Wait, now it’s a finished TODO item. Wait, now the TODO has a sub-TODO. Since it’s a text editor, it’s super-easy to create/edit/manipulate TODOs.
  2. Create an infinite hierarchy of tasks. Org-mode has no limit on the number of sub-tasks, sub-sub-tasks, sub-sub-sub-tasks, etc. (Sub-tasks rock because you can’t complete a TODO until all it’s sub-tasks are done, so its uber-useful for keeping track of projects.)
  3. View upcoming, done, in-progress TODOs at the press of a button. And it’s also dead simple to move them around too.

These are the reasons why I’ve used org-mode at work for the past couple of years.

But enough about Emacs. What does it have to do with Reminderer? Well, Reminderer does Item 1 thanks to the grammar parser and with support for a “share” intent (note to self: don’t forget this uber-important feature). Item 2 and 3 will need to be features.

As of the time of this writing, I spent the weekend refactoring the grammar parser. Up next comes the database and the alarm system. Then the UI.