Have you ever worked with Rails’ migrations? They make database changes a breeze, don’t they? While every software release doesn’t necessarily involve a migration, when one does happen to make use of one, I’m always pleased on how easily things work out. Whether it’s to add new data or alter existing data structures, Rails migrations make evolving a datastore (be it an RDMBS or NoSQL one like MongoDB) painless.
When I recently found myself altering the data structure of a SQLite database for one of my Android apps, I found myself wishing there was some similar migration mechanism for Android as there is in Rails. Alas, I could fine none, so I did what any other developer would do: I wrote one.
Droid Migrate is a simple command line framework that generates and runs database migrations for your Android apps that use SQLite. A migration is encapsulated by a
DBVersion class that contains an
down method. The
up method is called for an upgrade and
down for a rollback. What those methods do is entirely up to you.
In addition, Droid Migrate generates a
DatabaseHelper class through which you obtain underlying connections to a SQLite instance – this is the canonical way to interact with SQLite in an Android app anyway, but with Droid Migrate, you get a specially enhanced
DatabaseHelper that determines which version of a target database instance is the most current and runs the appropriate migrations to bring the database to that version.
Thus, with your newly minted
DatabaseHelper class, you can still interact with your app’s database like you would normally, however, by using this class, all migrations are handled for you. Allow me to demonstrate.
I’ve created a simple app that doesn’t interact with any database at this point – it simply creates a
ListView that is intended to hold a list of records for viewing. You can find this app on Github if you’d like to follow along. Nevertheless, the app’s main Activity is shown below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
What I’d like to do is add the ability to interact with a SQLite database; plus, I’d like to be able to evolve the data model on subsequent releases. This is where Droid Migrate shines.
After I’ve installed Droid Migrate (simply clone or download the code, build it, and put it into your
PATH and create new environment variable dubbed
DROID_MIGRATE_HOME), I can initialize my app to use Droid Migrate by opening up a terminal in the root of my app and typing:
-d flag specifies the name of my desired database. I can optionally provide a package name via the
-p flag if I’d like my newly generated classes in a separate package from my main app.
If you take a look at your app’s code, you should notice a number of new things. First, you’ll see two new classes and a new jar file. The classes are the aforementioned
DatabaseHelper and a class dubbed
DBVersion1. The newly added jar file in your app’s
libs folder contains a few classes that correspond to Droid Migrate’s runtime dependencies – this jar is extremely compact at 4KB.
DatabaseHelper class is brutally simple:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
This class extends Droid Migrate’s
MigrationsDatabaseHelper, which ultimately extends Android’s
SQLiteOpenHelper so as I mentioned earlier, you’ve got everything you need to interact with SQLite at your fingertips via
DatabaseHelper. If you look closely, you’ll see that this class makes use of a specialized XML file (that is ultimately generated into your
Take a look in the
res/values folder and open up the newly created
migrations.xml file. It should look something like this:
1 2 3 4 5 6
Note the value of
database_version – it’s 1. This corresponds to the
DBVersion1 class that was generated. Take a look at that class:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
This class is where you implement your initial migration, which would create various tables and populate them. Use the
execSQL method to pass in a valid SQL
String. For example, I’ll create an initial migration like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
As you can see, my
up method creates a table and inserts one record. My
down method rolls things back, which in this case means dropping the created table.
Now all I have to do is make use of my app’s
DatabaseHelper instance and Droid Migrate will ensure things are properly initialized. Therefore, I’ll update the original Activity to display a list of what’s in the database, which I know only to be one record based upon my initial migration.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
As you can see from the code above, the app now makes a query to the underlying SQLite instance and builds a
ListView from the result set of the query.
The key line is how the
SQLiteDatabase instance is obtained:
this.db = (new DatabaseHelper(this)).getWritableDatabase(); – that is where all the magic takes place. Droid Migrate passes along the version number to the Android platform and if there is a change, the Android platform will call a series of life-cycle methods, which Droid Migrate wires up with your migrations.
For instance, let’s imagine that a subsequent release of this app adds more data to the
hops table. Therefore, I’ll generate a new migration. This is done by typing the following command within the root directory of your project like so:
up flag signifies an increase in the database version (i.e. version++) and
down indicates a rollback (i.e. version–). If you take a look at your app’s code, you’ll notice a new class:
DBVersion2 and your
migrations.xml file has been updated: the
database_version value is now 2.
I’ll implement my
DBVersion2 class like so:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
Now if I fire up my app, the
ListView will have 2 items in it!
What about if you need to rollback? That’s just as easy. Imagine that the addition of that second row of data was a gigantic mistake and instead I really only want one row (i.e. I only want the data originally created in
DBVersion1). All I have to do is type within the root of my project:
After typing the above command, you should see the following output:
1 2 3
The only thing that’ll change in your project is the
migrations.xml file – the
database_version value will be rolled back to 1 (or what ever 1 minus the current version is).
Fire the app back up, and behold: one value is displayed because
down method was executed!
Droid Migrate makes upgrades and rollbacks to your underlying SQLite database a breeze; what’s more, it can handle upgrades or rollbacks beyond just one version. That is, if an app instance is upgraded from version 2 to version 6, each migration will be run in order (3, 4, 5, and 6). The same is true of a rollback.
If you are working with SQLite in an Android app, I highly recommend you take a look at Droid Migrate!