Android and openness

On Thursday I gave a talk at TriLUG. The slides I used are available but will probably be rather cryptic without my accompanying commentary.

Although I understand that Google has had to contend with both the open source zealots and the closed-everything carriers, upon looking at the trend, I find Google’s actions getting more disturbing. Just as Android seems to be coming into its own and Google should have more power than ever to twist arms, Google seems to be wimping out – or turning evil. I hope I’m wrong and they’re just waiting for the right time.

One thing I completely forgot to talk about is the abandoning of the Nexus One. When it came out, it was supposed to herald a new age of cross-carrier, stock-Android phones (with a built-in connection-sharing capability, no less). Only T-Mobile really picked it up – you could use it on AT&T but without 3G. Verizon and Sprint were supposed to be coming out with support for the same concept and just a different radio, but instead they released their own phones, with the usual modifications and constraints. So why did Google let them? They didn’t have to; the Skyhook case shows that Google can essentially pull their blessing from any phone for any reason. An Android phone without the Google apps isn’t going to be very attractive to consumers. Why didn’t Google force Verizon and Sprint to kowtow to the Nexus One before allowing them to release any more Android phones?

Advertisements

Is this thing on? ::feedback:: ouch…

Well – I don’t want to let the *entire* month of March go by without a post. I just haven’t done much with tech this month, though. It sucked. But evidently my absence has caused a surge in popularity, according to my stats. Less is more?

If I remember correctly – is Honeycomb the first version of Android where we actually saw a preview, got to fiddle with the SDK platform preview before it was actually embodied in a device? If so, better late than never, and let’s hope it means we’re on the way to seeing more of a community effort. Hey, it took a while for Red Hat to learn with Fedora, too, and they didn’t have voracious proprietary partners to contend with.

I have a meetup or two to arrange, but I hope I get some time to work further with ORMlite shortly.

Happy April Fools Day tomorrow!

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.

quick look at ActiveAndroid #androiddev

Just checking out ActiveAndroid, and while it seems to do a lot to make Android DB access easier, a few criticisms appear right up front:

  • Doesn’t having to extend the proprietary base class as your Application class seem a little… invasive? It’s like saying, this isn’t my application, this is an ActiveAndroid application!
  • I’m sure it wasn’t intended this way, but looking at the licensing terms:

The SOFTWARE PRODUCT is licensed as follows:
(a) Installation and Use.
Michael Pardo grants you the right to install and use copies of the SOFTWARE PRODUCT on your computer running a validly licensed copy of the operating system for which the SOFTWARE PRODUCT was designed [e.g., Windows 95, Windows NT, Windows 98, Windows 2000, Windows 2003, Windows XP, Windows ME, Windows Vista].

Let’s ignore for the moment the question of what OS this intended for… but isn’t this JAR going to be built into our app? Doesn’t this technically mean we can’t distribute the app?

  • This is based on reflection, right? So isn’t that gonna be kind of slow on Android?

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?