I can’t possibly do this job unless I get my hands dirty with Android technology, and then keep them that way. To start this process I just wrote a little utility app called LifeSaver (source here), which scratches one of my own personal Android itches. It’s in the Android Market and maybe someone else will find it useful. I think the lessons I learned in the process are more interesting and useful than the app itself.
What It Does · When you get a new Android phone, you tell it your Google login and password and a few minutes later there are your email history and contacts and schedule, it’s slick as slick can be. What doesn’t come over from your old phone is the history of your phone calls and SMS messages. I don’t know about you, but that stuff is an important slice of my life.
So, you run LifeSaver on your old phone and it copies that slice of life onto your SD card. Move the SD card onto your new phone — a good idea because it’s probably holding your music and movies and so on anyhow — then run LifeSaver again, and it rebuilds your history.
It doesn’t do much, but I immodestly think it looks kind of cool, with a certain amount of eye candy to entertain you while the data’s copied in and out (which can take quite a few seconds).
Now, it’s a great big stinking bug that I’m persisting onto an SD Card rather than into the cloud. In fact, I’m increasingly convinced that any data whose permanent canonical home is on a device that lives in your pocket and can fall into a toilet or the hands of a thief means You’re Doing It Wrong.
That granted, I’m now a person who’s going to be migrating from phone to phone pretty rapidly, and I’m going to find LifeSaver handy.
Elapsed Time · This took me five weeks to deliver, and even though I was distracted by working hard learning how to Google, there’s really not that much there there, and it could have been done in a handful of days if I hadn’t got distracted into working on how (or maybe how not) to iterate an Android Content Provider.
Well, that, and fit and finish. I spent at least 50% of my productive cycles on the appearance and interaction. This included:
Getting the animations working.
Figuring out how to manage a good-looking progress bar.
Learning how to style Android text.
Getting all the screens and animations working properly in both portrait and landscape modes.
What I Learned · In no particular order.
All that beautification time was well-spent. This is important; I think that, at the moment, the iPhone community works harder at fit-and-finish, look-and-feel, and user experience than we do on the Android side. Which is unacceptable.
But I didn’t really take this seriously, because if I did, I’d have hired a real designer to enhance my caring about the subject with actual professional taste and talent.
ProgressBars are a bit more work than you might think, and aren’t that flexible (for example, it’s hard to have any color but yellow), but if a user’s ever going to have to wait for your software, you owe them a good one.
If you want to use a ProgressBar, you have to do the work you’re reporting on in a background thread’s Runnable, and if you want to update the labels or whatever in the screen, you have to send messages to the UI thread. Can you smell concurrency bugs? I couldn’t, until one bit me. Don’t use an accumulator variable to accumulate the next total while a thread is still using it to refresh the screen with the last total. Sigh.
Suppose for one reason or another you want to store a message you’ve just
made up in the phone’s SMS log. The Content Provider’s address is
content://sms/; then you use the
method. The trick is that the
thread_id field has to be supplied
and has to have a value of zero. Then the system will automatically
create new SMS conversations as appropriate.
The bad news is that I had to spelunk through the Telephony provider source code for some hours to figure these details out. The very good news is that, as will always happen in a reasonably complex piece of software, when the documentation misses a detail, in the world of Open Source you can eventually always find the missing piece.
My attempt to use reflection to sweep the details under an
Iterable rug was slick, but involved heavy use of Reflection
code which it turns out is just too expensive in Android today.
My plan-B approach, which you can see in
is perhaps not as eye-pleasing, but seems to get the job done. I smell an
opportunity for more innovation here.
In general, the Android SDK could be a little more helpful when you
lack a necessary permission. This time, I spun my wheels for the longest
not because writing to the SD Card requires
WRITE_EXTERNAL_STORAGE, but because on some occasions it
doesn’t require that permission.
This was my first time actually putting something in the Android Market. It makes you cross a lot of t’s and dot a lot of i’s, but there’s no real rocket science involved; you’ll get there eventually.
Eclipse is probably a decent default choice for android SDK IDE just because there are a kazillion people out there who know how to use it, but I found it unsatisfying after several years of living largely in NetBeans, now an Oracle property.
On the Mac, NetBeans is substantially faster and more complete and better integrated. And did I say faster? I hope we can keep the IDE space from becoming a monoculture, so there will be competitive pressures to help ease this sort of strain.
Android’s Animations are just terrific; easy to use and snappy and composable and look great.
For persisting the data, I encoded it in JSON. Worked great. The only irritant was the JSONObject class’ excessive propensity for checked exceptions.
There’s just no excuse to have literal strings in your code, when it’s easy to stash ’em off in an XML sidecar and thus be set up for internationalization.
I’ve written this before, but I eventually ended up doing almost all my test runs on a physical Nexus One USB’ed into my computer, rather than on the emulator. It’s about the same speed and immensely more satisfying. And if you need to test on a naked phone with no accumulated data, well, there’s the emulator.
This project is largely TDD-free. Mea maxima culpa; I have no excuses. There is work going on to make TDD easier and more comprehensive for Android app developers, and I hereby promise that for my next project, whatever it is, I’ll put that through its paces.
The Important Lesson · Writing Android apps is, generally speaking, easy and straightforward. And it’s just total fun to watch your own code animating a screen that lives in your own pocket.