Trying out OrmLite by migrating LogMyLife #androiddev

In addition to ActiveAndroid I also took a look at OrmLite for Android. It’s a little larger than ActiveAndroid, but doesn’t dwarf my project like DB4O would. And the license is right for an open source dude like myself. Also it looks like it covers more functionality, also allowing you to get at the native DB connection (which doesn’t look possible with ActiveAndroid). And you aren’t required to subclass anything, though convenience base classes are provided. All good stuff.

When I tried out the demo project (which I also used in my TriDroid presentation), it looked reasonably straightforward. So just now I downloaded the JAR to take a look at what it would look like to convert LogMyLife to use OrmLite. What I didn’t notice is that the demo project is based on version 4.6, while the current version has jumped up to 4.10 a few days ago, which is apparently a significant release. I figured out things were different pretty quickly, though, because the first time I tried to annotate a DTO, the @DatabaseTable annotation couldn’t be found. I needed to download and link the ormlite-core JAR in addition to the ormlite-android JAR (which would be all that’s needed in previous releases). I suppose if I were using a maven POM to manage my build this would all be taken care of… but I haven’t gotten around to that.

I hope the docs are still reasonably accurate… I might be a little bit of a guinea pig for this release. We’ll see.

Bringing in the OrmLite helper

So I just went down a long rabbit trail about where exactly to put the OrmLite plumbing. The examples all have a helper that you have to keep track of per-Activity. But didn’t I just demonstrate for myself that an application-wide DB handle worked fine? So I’m thinking about just putting the plumbing in my Application subclass and seeing what happens. The complication seems to be multi-threading – the Google Group had a discussion pointing to this really interesting article on concurrent Sqlite access. I don’t really have multiple threads accessing the DB in LogMyLife, with the possible exception of my broadcast handlers – I’m not actually sure if they come in as a separate thread, or even a separate process, or what. That’s something for me to figure out soon. In the meantime, I guess I’ll go ahead with my scheme to try it in my Application class.

So first, I have to define a helper with callbacks for when I’m opening a connection and need to make sure the schema is in place, which needs to subclass OrmLiteSqliteOpenHelper (which subclasses the SqliteOpenHelper I’m used to) and define what to do in when the DB is being created or updated. Looks like it can also define some simple interactions for getting DAOs. This needs to be configured into the OpenHelperManager which is used to actually create my helper in context; the method of configuration is either to configure a string in my strings.xml and let magic happen behind the scenes, or to explicitly set a factory object on OHM that will return my helper. As it’s not much trouble and (I think) clearer, I do the latter.

Nuts and bolts

Soon I run into a little issue. OrmLite refers to SQLException all over the place, but it’s referring to java.sql.SQLException, generally used for JDBC, as opposed to the android.database.SQLException that’s usually used for Sqlite exceptions. It would be a nuisance just to have to be conscious of which is relevant. But the real difference is that the android.database.SQLException is a runtime exception, while java.sql.SQLException is a checked exception, so I have to deal with it somehow in any of my code that uses the DB. This forces me to re-think exception handling. Checked vs. un-checked exceptions is kind of an old argument, but I thought after all our experiences with Java the scales were starting to tip toward unchecked? As far as I know Java is the only major language using checked exceptions widely; the dynamic languages gaining popularity don’t really even have the ability to use them. So it’s kind of disheartening to see this throwback; although I imagine it arises from the JDBC nature of the rest of the OrmLite package.

Now I go to create a Dao by subclassing BaseDaoImpl, and I’m given a choice of four different constructors (but must include one). The most obvious-seeming one is evidently to be used with a DI container, so I look at the other ones. Eventually I realize that it’s probably best to use the one that’s like the generic DAO constructors, e.g. BaseDaoImpl.createDao(getConnectionSource(), Tracker.class).

While I’m working on the numerous errors Eclipse is reporting from my brutal refactoring, I realize that my BroadcastReceivers don’t have access to my Application subclass, so they have their own code for instantiating the DB connection. There’s no helper base class for them – reasonable, given they don’t really have a life-cycle. Suddenly just defining a string looks like a much nicer path for configuring the helper class.

An example query

And now I come up against one of my first query refactorings. I have a method like so in my existing domain code:

public Alert fetchNextAlert() {
 return fetchAlert(
  db_ALERT_ENABLED + " = 1 AND " + db_ALERT_SKIP_NEXT + " != 1 AND " +
  db_ALERT_NEXT_TIME + " > datetime('now', 'localtime')",
  null, null, null, db_ALERT_NEXT_TIME + " ASC", "1"
 );
}

fetchAlert takes these raw SQL constraints and turns them into a query for a single row from the Alerts table, then converts that row into an Alert DTO. It’s all fairly ugly code, to be sure. Here’s my first crack at a replacement in my OrmLite DAO:

public Alert fetchNextAlert() throws SQLException { 
 return queryForFirst(queryBuilder()
  .orderBy(C.db_ALERT_NEXT_TIME, true)
  .limit(1)
  .where().eq(C.db_ALERT_ENABLED, true)
  .and().ne(C.db_ALERT_SKIP_NEXT, true)
  .and().gt(C.db_ALERT_NEXT_TIME, new Date())
  .prepare());    
 }

Now this is reasonably clear and concise, and in line with how other ORM libraries work. But one thing troubles me: as far as I can tell, there’s no way to get raw SQL in as part of a where clause; I couldn’t duplicate the ” > datetime(‘now’, ‘localtime’)” constraint, and in my experience, when it comes to time, you want to speak the DB’s language. But perhaps I’m wrong this time – certainly the code above captures the intent. If absolutely needed, I could run a raw query to return the ID of the Alert I want, then just use standard DAO methods to turn that into an Alert DTO; two queries instead of one, though.

I have reasonably-sized swaths of code compiling at this point; time for a break.

Intercepting SimpleCursorAdapter data #androiddev

Normally when you create a SimpleCursorAdapter for a ListView, you specify a one-to-one mapping of the columns from the DB and the views where you want them to end up, and the adapter basically just does a toString() on your data and sticks it in the view.

You can, of course, modify this behavior by overriding setViewText, which lets you reformat the text or modify the view as you wish; but it doesn’t give you the DB cursor, just a String, so you can’t pull the data yourself or refer to other columns. But not to despair (or turn to the NotSoSimpleCursorAdapter)! You can modify anything you want by providing a ViewBinder to the adapter.

The main reason I’m talking about this is because I think the documentation on this is just a little vague:

An easy adapter to map columns from a cursor to TextViews or ImageViews defined in an XML file. You can specify which columns you want, which views you want to display the columns, and the XML file that defines the appearance of these views. Binding occurs in two phases. First, if a SimpleCursorAdapter.ViewBinder is available, setViewValue(android.view.View, android.database.Cursor, int) is invoked. If the returned value is true, binding has occured. If the returned value is false and the view to bind is a TextView, setViewText(TextView, String) is invoked. If the returned value is false and the view to bind is an ImageView, setViewImage(ImageView, String) is invoked. If no appropriate binding can be found, an IllegalStateException is thrown.

OK, great. This also promises that you can put any kind of data in any kind of view (not just a TextView). But I didn’t know what it meant by “if a SimpleCursorAdapter.ViewBinder is available.” Turns out it’s pretty simple:

  1. Implement the SimpleCursorAdapter.ViewBinder interface (it has only one method, setViewValue, which gives you the Cursor and the view to work with – and just return false to let the adapter’s default behavior handle the binding). I did this for LogCursorAdapter in an inner class.
  2. Instantiate your implementation and use setViewBinder on your SimpleCursorAdapter instance to set it up as the binder. This makes it “available” for the process described above.

This is arguably better than overriding setViewText because you wouldn’t even have to subclass the adapter to do it – or even create a class (it could be an anonymous implementation). And of course you can access all of the cursor columns in any way you please. Nice.

As far as my earlier data retrieval woes, this gave me the ability to pull data out the way I wanted. Sqlite seems to be storing plenty of precision in the NUMERIC column type; it was just a matter of it being retrieved as a String that caused truncation of precision. In this case the solution was just to pull it out as a Long or Double as appropriate and format it myself (I also learned about DecimalFormat which was very helpful).

LogMyLife alpha release – try it out!

It’s time for LogMyLife to see the light of day outside my house – I’m calling it alpha-ready today. Go check it out. I’ve had it with fiddling around and no one seeing the results :-) It’s actually pretty functional, but it’s not as pretty as it could be and I know there are a few corner cases where things are a little wonky. And there’s so much functionality left to add… but it’s been a great project for me to familiarize myself with a lot of Android UI. And that will continue.

Some interesting stuff I just learned recently:

What’s in a name?

The application name and the name you see on its home screen/launcher icon need not match (though it’s probably wisest if they do). The application has a label in the manifest, and so does each activity (potentially).

If you look up the application in the settings page, it will show the application name (probably also in any market interactions). The launcher icon will show the label on the launcher activity. Presumably this is because you could conceivably have multiple launching activities for the same app (different entry points).

In my case, I wanted to show a different label (“LogMyLife – Main”) to the user once they launch the app than the application name (“LogMyLife”), so they’re oriented once they return; so I just created a shell activity (“Launcher”) with the correct app label which simply replaces itself with the real front Activity, just so I could get the labelling right. There’s probably a better way, like changing the label once the activity launches. In fact, I just tried that out (setTitle at the beginning of onCreate) and it works fine. Heh – live and learn.

Also interestingly, when I noticed this and changed the label, Android didn’t handle the change very well, at least in the 1.5 emulator where I test this (likely fixed since). The icon with the old label remained, but it wouldn’t actually load the app (error), and there was no new icon/label. I had to un-install and re-install the app to get it to launch properly.

Displaying DB data

I was going to follow up a bit on my last post, but I think I’ll do it with another post.

Onward

Anyway, the release is out there, so please let me know what you think of it. And feel free to hack it up if you want to see your own improvements! Github can have your own clone set up in seconds.

I may start working on the website for this sooner rather than later. SpringSource released some kind of library to assist with Android so I’m itching to try it out!

Mangling data with sqlite on Android

Oof! I still haven’t recovered from the holidays.

I nearly have LogMyLife in a presentable state, but I just have this one last nit to pick: numbers don’t seem to get recorded the way I expect. I’m using a numerical column (with the intention of using the DB to manipulate numerical values later) but they weren’t storing with the precision I expected.

To explore this, I created a demo project on github. It’s a simple Android app that lets you try out storing values in different ways. It’s interesting for exploring edge cases. I’d like to say more about this but it’s late… maybe later. One answer I was looking for: when you store the value 1.23456789 into a numeric column, if you retrieve it as a String, you get 1.23457; as a Float, 1.2345679; if you retrieve it as a Double you get the full precision. When retrieved as a String it’s getting truncated with only six digits of precision – why?

Import/Export for LogMyLife #androiddev

Over the past few nights I whipped out an import/export capability for LogMyLife. Right now all it does is basically package up the database and a version file; later I expect I’ll include saving properties, which is why I’m including format version in the archive (I thought that was good foresight, as who knows what else might change). I wrapped it up in an activity you can call from the menu of the Main activity.

The implementation is reasonably straightforward, although I didn’t know a thing about handling files from Java. It’s predictably verbose but not too outrageous. I got a lot of help from this StackOverflow entry and this sun.com article. If you’re thinking of doing this you might check out how I did it for inspiration. I’d certainly encourage everyone to provide this capability so users can back up and transfer their app data!

I faced an odd little problem on importing: of course, it replaces the app’s DB. When I returned to the main activity, I returned a result code indicating this had happened, and had it close the database handle and reinitialize the components that displayed information from the database. But something seemed to be holding on to a database cursor and requerying it, and I couldn’t quite figure out why that was happening. Eventually I decided it would probably be simplest if I just have the activity restart itself from scratch. An answer on StackOverflow helped with how to do that – it’s not totally obvious; basically, just finish() the activity, and then (before exiting the same method) start it again.

Gingerbread is out, woo! And the Nexus S is coming; but I want a phone with a keyboard, dammit. Once my Nexus One gets 2.3 I’ll likely try to sell it in favor of the G2. Even though tethering is extra, which is wrong and bad and to be vehemently discouraged, but I don’t use tethering anyway.

Exploring ApiDemos; misc Android

Android 1.5 is down below 8% market share. If my wife’s Cliq ever gets an upgrade I’m dropping that platform like a hot potato. What’s interesting is that Eclair is actually still more common than Froyo (40%) – you’d think if they’ve done the work to get the device to 2.1, and seen how quickly versions change, it shouldn’t be too big a step to 2.2. Oh well.

I’ve been looking through ApiDemos to learn. While most of the demo classes seem well-commented, amusingly the ApiDemos.java file itself is not, and it does some non-obvious things involving searching the package manager for intents to dynamically create the lists being browsed. The upshot is it’s less than obvious how to find the sample code that matches the sample functionality you browse to – nothing tells you how to make the mapping, and it’s not always obvious. The actual mapping is between the label listed in the AndroidManifest.xml file for the activity (which is what you see in the app’s list browser, except that in many cases the actual text is in the strings.xml file) and the class name listed with it, e.g.:

<activity android:name=".view.Tabs1" android:label="Views/Tabs/Content By Id">

I would argue that the mapping between what you see (Views/Tabs/Content By Id – which again is often in strings.xml for no good reason I can see) and the class (com.example.android.apis.view.Tabs1) is far from obvious. Call me crazy, I think a README or at least a couple lines of comments in the main class would be in order. I should submit a patch.

Found a little nugget in ApiDemosApplication.java (which is otherwise empty):

PreferenceManager.setDefaultValues(this, R.xml.default_values, false);

This is a one-time setting of default prefs. Now of course, default_values.xml couldn’t be something simple like key-value pairs. It’s a PreferenceScreen like you would use for defining a PreferenceActivity. You wouldn’t know about those from the dev guide, unless you like decyphering reference docs. But as it happens I learned about these at some point and created a prefs screen with them in LogMyLife… which currently has no effect, so I need to do something about that.

I finally got around to gathering sources for the 2.2 platform to attach in Eclipse. I’ll have to update my article one of these days. Aside from the new sources, I should include the Apache license files in order to be proper.

I’m looking at migrating this blog to Blogspot. WordPress has neat themes but it deliberately blocks integration with tools like Adsense and Google Analytics. Also this editor drives me nuts. We’ll see.

Permissions automatically added to android app manifest

Last week when I displayed a QR code to download my app, the one person who talked to me about it was a security person, and of course she asked: why does it need these permissions?

Storage: modify/delete SD card contents. Phone calls: read phone state and identity

Say what? I didn't ask for those!

Truth be told, I had no idea (except for the start-at-boot, which is in the manifest and needed so it can install alarms at boot). I noticed them when I did a test install but didn’t think much about it because I was in a hurry. No, LogMyLife doesn’t need to write to the SD card or read the phone identity. OK, it will need to write to SD once I implement export/import of data; but it will never need to read the phone identity.

Tonight I finally got a chance to look into this. It turns out, if you build your app to run on the 1.5 platform (which LogMyLife does so that my wife’s Cliq can use it), these permissions are silently added when the APK is created. Believe it or not this is “working as designed” according to this Google Code issue. Romain Guy could have been a little more helpful there and provided a link to some kind of useful explanation, but I get the drift: because these permissions were introduced in 1.6, they’re grandfathered in to apps built for previous versions (which didn’t have to declare them), and so have to be included for them to work on platforms 1.6 and up, just in case they’re needed.

There’s some kind of voodoo in the Android Market that keeps these added permissions from showing up at download/install time. But they’re still technically there, and they’ll show up if the user looks at the application permissions later. Also they’ll show up at install via non-Market path, like during beta testing. Sigh! Fortunately, or un-fortunately, most users are pretty oblivious to permissions. But not security people.

So, what to do? I could exclude my wife and the other unfortunates stuck on 1.5 and just target 1.6+. Perhaps I could provide different APKs, one just for 1.5, and another for 1.6+? Well, regardless of that, what I think every app author should be doing is explaining exactly what they’re doing with those permissions. I’ll include a section in the app README, and also in the Market description (once it’s on there), explaining what permissions are used and why, and I can explain where these two come from if needed.