Being a small morsel of Android-specific geek entertainment involving an example of the kind of thinking that being a Rubyist provokes which however may be grievously wrong.
[This is part of the Android Diary.]

What happened was, I’m writing a little Android app to get my hand back in, which makes considerable use of Android Content Providers.

The Problem · Content providers (I’ll just say “Providers” from here on in) are a good idea, and allow you do to do some things in Android that would be awkward or impossible in other frameworks. A Provider is identified by what Android calls a Uri, and even though I’m pretty sure it isn’t really a URI, it’s a good thing to name data resources with short structured strings.

In practice, Providers front-end relational tables usually backed by SQLite, which is baked into every Android device. You provide the Uri, SQL SELECT and ORDER BY clauses, and the Provider gives you back a Cursor, which can be used to store and retrieve rows from the table.

The problem is, the API is sort of verbose and I always end up with lots of boilerplate. The Cursor has moveToFirst()/moveToNext()/isAfterLast() methods so you end up with a do while loop, and then there are methods for retrieving fields; you have to provide a data type and a column number, and it also will provide a list of the column names in order.

Since I’m an Object-Oriented kind of guy, I’d like to have an object representing whatever-it-is that’s coming out of the content provider, and, given the name of the fields I care about and their types, that should be enough to do the job.

com.google.providerhelper · That’s what I called the code. Because it says Google on my business card, can I now say package com.google... without asking anyone? I may have to apologize later which as they say is better than asking for permission first.

Anyhow, the code’s on Google Code; before I provide that link, check out the JavaDocs, which I haven’t yet figured out how to stage there. First look at the Reader class and enjoy the simplicity of for (call : calls), and then check out the Builder class that it relies on.

To summarize: make a class that extends Builder, equip it with setXxx() methods for every xxx field in some ContentProvider that you care about, and it’ll take care of looping the Cursor and making the right getter calls against it and calling your setters.

It’s all done with sneaky metaprogramming tricks; for a statically-typed system, the Java language and Harmony libraries can be coerced into considerable dynamism if you hold ’em down and twist their arms. Those who care for such things may be amused by Builder.java and Reader.java.

Warning 1: For Java Programmers · This is what a couple of years of living in the world of Ruby can make you think are reasonable programming techniques. Of course, in Ruby, the required metaprogramming would have occupied a quarter the code and wouldn’t have required the developer to provide those setter methods. You’ve been warned.

Warning 2: For Androiders · Before sharing this with you, I sent a note to Reto Meier, my personal Android application-programming guru, entitled “Is this sick & twisted?”.

His reply included bad news (“Your solution... makes me nervous”) and good news (“it's such a convenient way to iterate over a cursor that the temptation will be to always use it”). I found his answer extremely educational; he’s written it up at Content Provider Iterator (or Things That Make Me Nervous). Check that out, and I’ll return to the conversation next week after I’ve had a chance to think some more.



Contributions

Comment feed for ongoing:Comments feed

From: Martin Probst (Apr 14 2010, at 04:03)

One of the things that really annoys me with such frameworks (and this is not a criticism of your code in particular) is that they always force you to use stupid Java Beans with setters all over the place.

Java Beans are an anti pattern - we have constructors on objects so that we can establish invariants on their fields: for example, a Call will always have properly set up "number" and "date" fields that are constant over the objects lifetime.

Establishing such invariants is one of the things that prevents a huge number of bugs due to unexpected state changes in objects, it allows to reason much more easily about concurrency (immutable objects), and makes code easier to understand.

Speaking of concurrency btw, you realise that your code isn't threadsafe, right?

The root cause of this Java Beans epidemic is of course that Java reflection doesn't provide method parameter names, and in particular not the constructor parameter names that would be helpful here. That was planned for Java 6 at some point of time but never happened, not even for Java 7. Sigh.

[link]

From: len (Apr 14 2010, at 07:42)

I like this series. Discovery and contrast in pursuit of clarity.

[link]

From: Jay Gischer (Apr 14 2010, at 08:51)

I've spent a couple years in the Ruby/Rails world, and I can really relate to the reasons you wrote this. I find myself jonesing for ActiveRecord.

At the same time, now that I look at it, it involves copying all the data in the cursor. That could become a bad thing at some point. Using lots of memory either means very little or else it kills you, performance wise.

One other concern is that the silent failure in findSetters when one of the setters is missing or misspelled is maybe arguably what you want in production, though I doubt it, but it's definitely not what you want in testing.

[link]

From: John Hart (Apr 14 2010, at 12:33)

I'm with Martin on this one - Java Beans are awful with all the getters & setters. Makes you think that the guys who invented Java sell keyboards on the side, to replace the ones that wear out.

If you're going to use reflection, why not just declare your data objects as structs and directly set the fields (rather than calling the setXXX methods)?

Less flexible, but much more readable, and closer (IMHO) to a dynamic language approach.

I actually did this all the time in C#, back when I had to bake my own relation-object mappings...

[link]

From: Randy (Apr 14 2010, at 15:00)

I find myself wishing I could write android apps with the latest iteration of c# with linq. No cursors....

[link]

From: Aaron (Apr 14 2010, at 21:22)

I get a sense that much of the Android API quirkiness is driven by performance consideration.

This looks like no exception (although I have no experience with this API). I wouldn't use your method chart hundreds of rows of stock data for example.

Is moveToFirst() necessary? Couldn't you just use moveToNext()?

while (cursor.moveToNext())

{

//...

}

$0.02

[link]

From: John Dougan (Apr 14 2010, at 21:32)

Boy howdy, do stories like this make me miss NewtonScript.

[link]

From: Jarrett Vance (Apr 15 2010, at 13:47)

The sacrifices in productivity you must make for performance reasons is unappealing (but still better than managing memory).

http://developer.android.com/guide/practices/design/performance.html

I imagine the content provider API would be more terse, and powerful with proper generics.

I too wish I could use C# with it's well designed generics and lambdas on top of the CLR. C# code runs faster on Android than Java and will continue even after JIT comes to Android.

http://www.koushikdutta.com/2009/01/dalvik-vs-mono.html

I'm personally excited about the mono team working on MonoDroid.

http://tirania.org/blog/archive/2010/Feb-17.html

[link]

From: Robert Wittams (Apr 15 2010, at 18:04)

Surely the right solution here is constructor argument annotations. No setters, immutable objects, no name construction.

eg

class Thing{

...

public Thing(@Provided("id") int id,

@Provided("address") String address) {...}

}

Annotations don't get lost in dalvik do they?

[link]

From: Jerome Lacoste (Apr 16 2010, at 03:11)

Some comments:

* can't you make the row class a plain Pojo, not inheriting from Builder ? I like things to be as independent as possible. Builder would take a class as parameter

* also provide an alternative with a 'hardcoded' loader.

* we can also try to reuse the same "row instance" (that way you do away with re-allocating memory). If you the client needs to keep the values, clone the instance or chose to not reuse the instance.

I've implemented these changes here:

http://github.com/lacostej/android-providerhelper/

I've also made some performance tests, and and the results (including code) are in the README file. Summary: about x10 slower with the GenericLoader compared to raw Cursor usage. Ouch !

But using a hardcoded Loader seems to be OK when it comes to performance. Maybe not to your liking, but I think this pattern isn't a bad idea.

[link]

From: Mike Jennings (Apr 16 2010, at 11:07)

I think readability and abstraction should always come before performance. Smart people can always make readable code run faster later, and readable code helps you see larger patterns that you might otherwise not see if you are adrift in a sea of boilerplate.

[link]

author · Dad
colophon · rights
picture of the day
April 13, 2010
· Technology (90 fragments)
· · Android (64 more)

By .

The opinions expressed here
are my own, and no other party
necessarily agrees with them.

A full disclosure of my
professional interests is
on the author page.

I’m on Mastodon!