Android database migrations are very peculiar. The database does not update until you open it for the first time, but you usually don’t open it until you are ready to use it in an
Activity. If the database update scripts take a while to run (ie: migrating data to a new structure), you could be holding up your activity. The update may even trigger an “Application Not Responding” error. What is the best way to handle this? This post will describe how this situation was addressed in the HikeBesideMe app. Make sure you check out my previous post on schema migration in Android.
The first attempt was to perform the time-intensive data migration as an AsyncTask during the schema patching. This appeared to work okay on Gingerbread (v2.3.7). One odd side-effect was missing display data. This was due to the fact that the activity loaded the data before all of the data migration had occurred. In our use-case, the missing data was trivial. I did not approve of this 100%, but thought it only a minor annoyance. Besides, the data would be available the next time the user entered the activity.
However I ran into issues on Ice Cream Sandwhich (v4.0.2). If the user attempted to open an activity that read the data being migrated, a locking error would occur. This caused the app to force close. Obviously that is not good. I did not fully investigate why the locking error was happening. If someone knows, please comment below. I was now forced had to find another solution. I prefer my final solution a lot better.
I will jump straight to the secret. The implementation details will follow below.
The app keeps track of the currently installed version in a shared preference. Upon opening the app, the main activity checks the stored version with the current version of the app. If the two do not match, then the app shows a progress dialog box while it opens the database. After a successful database upgrade, the app then stores the current version in the shared preferences. Upon subsequent start-ups, the application versions will match, and the process dialog box will not be shown. Pretty simple and straight-forward.
First, create two class-level variables for the two version numbers to compare. Also create a variable to store the reference to the preferences.
onCreate method, look up the current version and get a hold of a reference to the preferences.
Finally, in the
onResume method, do the following.
This will retrieve the stored version and then check it against the current version. If they are different, then an asyncronous task is executed to open the database. After the database opens (and thus, updates), the
onPostExecute method will save the current version as a preference and close the process dialog.
You could further extend the AsyncTask to safely update other components of the application. I personally have not encountered any updates that might require special handling. If you have, please comment on that as well.