Last week I wrote Content Provider Iterator, which simplifies the task of dealing with Android’s Content Providers. Reto Meier, the author of what is currently the best Android developer book, got all nervous about my approach. He’s got a point, but so do I.

If you haven’t read Reto’s piece, please hop on over there and do so; I’ll wait till you get back.

To recap; my providerhelper package lets you write the following code:

Reader<Call> calls = 
    new Reader<Call>(Call.class, activity, CallLog.Calls.CONTENT_URI);
for (Call call : calls)
  String number = call.getnumber();

I claim that this is about as idiomatic as you can possibly get, if your idiom is Java’s flavor of object-orientation.

But On the Other Hand · Reto, and others, point out that this creates a lot of objects (one per Call, plus one for any field you choose to store in an Object field) and does a lot of reflection (one method.invoke() for each field you want to extract from the Cursor, for each Call). This, they argue, will have an unacceptable cost and flies in the face of the official recommendations on designing for performance in Android.

Jerome Lacoste actually wrote some code to measure the performance, and it suggested that the slowdown was as much as a factor of ten. So this is not just a theoretical problem. I guess those people who wrote the Design-for-performance guidelines knew what they were talking about.

Well, for some applications, anyhow. The problem is, for others it’s not going to make a damn bit of difference. For example, in my own app code, the delay for reading a few hundred records out of the phone-call log, and doing a bit more work with them than Jerome did, isn’t even measurable. (I’m working to reconcile my result with his; something funny is going on).

At a more general level, I’d like to appeal to Knuth’s Premature optimization is the root of all evil. What Knuth didn’t say, as far as I know, was the reason why his statement is true: nobody is smart enough to predict where the performance bottlenecks will occur in any reasonably complex application. And let’s grant that some “premature” optimization is common practice: as in, the selection of sensible algorithms and data structures.

So, my take-away is: Yes, you have to learn the lessons Reto’s teaching and be nervous about the things he says you should be nervous about.

Having said that, I still believe that the right way to build an application is to do the Simplest Thing That Could Possibly Work, and maybe it’ll be fast enough, and if it’s not, then don’t bloody guess where the problem is, measure it until you know.

Other Gripes · Reto and my commenters also point out that:

  • Getters and setters are often bad practice, and

  • the code isn’t thread-safe, and

  • developers shouldn’t have to inherit from Builder.

Those are all fair points, particularly the one about concurrency. I will update the package docs to include warnings about the potential performance problems and all these other gotchas.

What Next? · I’m not sure yet. On the one hand, Reto’s arguments and Jerome’s results are certainly sobering. On the other, I think the problem I was addressing is real: Having read quite a lot of Android apps source, I do think I see quite a bit of tedious ugly code concerned with pulling fields out of cursors; the kind of thing that has me thinking Don’t repeat yourself.

Having said that, I have to observe that the Google-provided apps work pretty well and run pretty fast, and the source code is a lot easier to read than that of a bunch of other open-source projects I could name. So maybe I’m straining at gnats here.

Maybe I’ll end up plastering a big Never do things like this all over that providerhelper code. Maybe I’ll find a way to do away with some boilerplate at a more acceptable cost. I’m quite positive that I’ll come away a deeper and better understanding of the Android SDK; this is by way of sharing the lessons.



Contributions

Comment feed for ongoing:Comments feed

From: Alexander Kosenkov (Apr 19 2010, at 02:55)

This mappig should be done in compile-time.

Look at JDO (like in google app engine) - it has post-compilation 'enrichment' step that does all the dirty binding work based on annotations.

I can imagine that it is possible to write JDO adapter for Android providers =) Anyway we have a lot of pre- and post-compilation processors, so another one will not harm.

[link]

From: JulesLt (Apr 19 2010, at 03:27)

The problem with taking Knuth to heart, is that you end up with designs that do incredibly bad things, which then need to be majorly unpicked.

The most common pattern has to be - doing thousands of action X rather than one action Y that acts on the group.

In particular, where X is a call outside the current runtime (so will not be improved by compiler or runtime improvements) and especially where X involves any kind of network call.

My rule of thumb - presume all network calls tend to infinity.

[link]

From: Michel S. (Apr 19 2010, at 04:10)

If only Java has macros; that way, you can write an iterator macro that is converted to performant code at compile time.

I wonder how easy it is to program Android using (non-idiomatic*) Clojure.

* idiomatic Clojure relies heavily on garbage-collecting short-lived objects, thanks to its data structures being immutable

[link]

From: David (Apr 19 2010, at 04:34)

One thing you have to remember with mobile - cycles => power => battery. Chewing up a few extra cycles to reduce development effort on a desktop application is often okay. On mobile, the cost can be substantial. I've seen charts of algorithm vs. battery life used in design decisions.

[link]

From: Scott Conner (Apr 19 2010, at 06:00)

It doesn't sound like your critics didn't like your idea, just that the implementation could be improved by cutting some low hanging fruit off the branch.

You said it yourself - it is idiomatic to a 'T' for Java, which is notorious for bad performance and unnecessary objects.

Reusing cached objects - using primitives where you can - and reducing reflection by implementing some sort of interface could definitely help.

I think you are doing a good job considering people's input, but try not to explain any of it away as none of anyone's criticisms said the problem you are trying to solve isn't real, or that a solution to it wouldn't be awesome.

[link]

From: Richard Sewell (Apr 19 2010, at 08:14)

I've tried (in a non-generic way) to wrap Cursor accesses in tidy objects in a couple of our Android projects, but it has always ended up in a tangle.

In my case, the problem has always been that (once I built an object to let me read the data) I couldn't resist giving it setter methods, and methods that did work that required changing the database.

Then the relationships between the object, the current row in the cursor, and the underlying database row become very complicated. I have made it work, but not in ways that I liked.

I really don't know if there is a way to make this nice (and I'm just too stupid to work it out) or if it is an intractable problem caused by the lifecycle of sql data.

Incidentally, our first Android project (where all the read access was wrapped in objects) had to be reworked to get acceptable ListView performance, to get rid of all the object allocations and so on in the ListView's data binding. It's all bare Cursor access in there now.

[link]

From: RodgerTheGreat (Apr 19 2010, at 10:38)

JulesLt: And recall that Knuth *also* said you should write a program, scrap it and start over at least once. Knuth didn't mean you shouldn't worry about optimizing production code, just that you should initially focus on getting things working and *then* see what you could do to improve performance.

[link]

From: Jerome Lacoste (Apr 20 2010, at 02:07)

I've tried to make a combination of the Iterator design and a hardcoded code-generated Loader class.

I've ran into issues. See http://github.com/lacostej/android-providerhelper/blob/0294db4129872101d2ecf0fbf33dc488603189a3/src/com/google/providerhelper/LoaderGenerator.java for comments and links.

Yet it seems that a simple ORM generator, a la ibator for ibatis, could be an interesting solution. I don't mind the one time cost code generation if that allows me to benefit from the coding style. Best of both worlds ? Good enough for me.

[link]

From: Pla (Apr 20 2010, at 07:51)

Designing for performance? http://code.google.com/p/android/issues/detail?id=7836

[link]

From: Paul W. Homer (Apr 20 2010, at 14:52)

From a readability perspective your version was definitely better. The cursor stuff is very ugly syntax, it clouds the intent. If that is what is best for performance, perhaps the language shouldn't be Object Oriented? After all, why use a specific language paradigm, if 'required' optimization forces you to continually abandon it?

[link]

From: Koppernicus (Apr 21 2010, at 05:23)

I like Tim's version much better. This whole argument reminds me of early versions of Java, where this kind of code caused conniptions. The best outcome would be for Google to improve Dalvik performance in both reflection and object creation so that it wouldn't matter.

[link]

From: Robert Young (Apr 21 2010, at 11:54)

-- perhaps the language shouldn't be Object Oriented? After all, why use a specific language paradigm, if 'required' optimization forces you to continually abandon it?

Thank you.

Now, if only the Koder Kiddies would accept that RDBMS is there to do the heavy lifting (sending object data over the wire, or better still, objects), and the client only to paint the pretty pictures, all these apps would run much quicker. Of course, that means specifying BCNF databases. Party like it's 1969.

[link]

author · Dad
colophon · rights
picture of the day
April 18, 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!