If your application requires a database and it comes with built in data, what is the best way to ship that application? Should I:
Precreate the SQLite database and include it in the
.apk
?Include the SQL commands with the application and have it create the database and insert the data on first use?
The drawbacks I see are:
Possible SQLite version mismatches might cause problems and I currently don't know where the database should go and how to access it.
It may take a really long time to create and populate the database on the device.
Any suggestions? Pointers to the documentation regarding any issues would be greatly appreciated.
Android already provides a version-aware approach of database management. This approach has been leveraged in the BARACUS framework for Android applications.
It enables you to manage the database along the entire version lifecycle of an app, beeing able to update the sqlite database from any prior version to the current one.
Also, it allows you to run hot-backups and hot-recovery of the SQLite.
I am not 100% sure, but a hot-recovery for a specific device may enable you to ship a prepared database in your app. But I am not sure about the database binary format which might be specific to certain devices, vendors or device generations.
Since the stuff is Apache License 2, feel free to reuse any part of the code, which can be found on github
EDIT :
If you only want to ship data, you might consider instantiating and persisting POJOs at the applications first start. BARACUS got a built-in support to this (Built-in key value store for configuration infos, e.g. "APP_FIRST_RUN" plus a after-context-bootstrap hook in order to run post-launch operations on the context). This enables you to have tight coupled data shipped with your app; in most cases this fitted to my use cases.
Currently there is no way to precreate an SQLite database to ship with your apk. The best you can do is save the appropriate SQL as a resource and run them from your application. Yes, this leads to duplication of data (same information exists as a resrouce and as a database) but there is no other way right now. The only mitigating factor is the apk file is compressed. My experience is 908KB compresses to less than 268KB.
The thread below has the best discussion/solution I have found with good sample code.
http://groups.google.com/group/android-developers/msg/9f455ae93a1cf152
I stored my CREATE statement as a string resource to be read with Context.getString() and ran it with SQLiteDatabse.execSQL().
I stored the data for my inserts in res/raw/inserts.sql (I created the sql file, 7000+ lines). Using the technique from the link above I entered a loop, read the file line by line and concactenated the data onto "INSERT INTO tbl VALUE " and did another SQLiteDatabase.execSQL(). No sense in saving 7000 "INSERT INTO tbl VALUE "s when they can just be concactenated on.
It takes about twenty seconds on the emulator, I do not know how long this would take on a real phone, but it only happens once, when the user first starts the application.
From what I've seen you should be be shipping a database that already has the tables setup and data. However if you want (and depending on the type of application you have) you can allow "upgrade database option". Then what you do is download the latest sqlite version, get the latest Insert/Create statements of a textfile hosted online, execute the statements and do a data transfer from the old db to the new one.
I wrote a library to simplify this process.
It will create a dataBase from
assets/databases/myDb.db
file. In addition you will get all those functionality:Clone it from github.
There are two options for creating and updating databases.
One is to create a database externally, then place it in the assets folder of the project and then copy the entire database from there. This is much quicker if the database has a lot of tables and other components. Upgrades are triggered by changing the database version number in the res/values/strings.xml file. Upgrades would then be accomplished by creating a new database externally, replacing the old database in the assets folder with the new database, saving the old database in internal storage under another name, copying the new database from the assets folder into internal storage, transferring all of the data from the old database (that was renamed earlier) into the new database and finally deleting the old database. You can create a database originally by using the SQLite Manager FireFox plugin to execute your creation sql statements.
The other option is to create a database internally from a sql file. This is not as quick but the delay would probably be unnoticeable to the users if the database has only a few tables. Upgrades are triggered by changing the database version number in the res/values/strings.xml file. Upgrades would then be accomplished by processing an upgrade sql file. The data in the database will remain unchanged except when its container is removed, for example dropping a table.
The example below demonstrates how to use either method.
Here is a sample create_database.sql file. It is to be placed in the assets folder of the project for the internal method or copied into the "Execute SQL' of SQLite Manager to create the database for the external method. (NOTE: Notice the comment about the table required by Android.)
Here is a sample update_database.sql file. It is to be placed in the assets folder of the project for the internal method or copied into the "Execute SQL' of SQLite Manager to create the database for the external method. (NOTE: Notice that all three types of SQL comments will be ignored by the sql parser that is included in this example.)
Here is an entry to add to the /res/values/strings.xml file for the database version number.
Here is an activity that accesses the database and then uses it. (Note: You might want to run the database code in a separate thread if it uses a lot of resources.)
Here is the database helper class where the database is created or updated if necessary. (NOTE: Android requires that you create a class that extends SQLiteOpenHelper in order to work with a Sqlite database.)
Here's the FileHelper class that contains methods for byte stream copying files and parsing sql files.
My solution neither uses any third-party library nor forces you to call custom methods on
SQLiteOpenHelper
subclass to initialize the database on creation. It also takes care of database upgrades as well. All that needs to be done is to subclassSQLiteOpenHelper
.Prerequisite:
android_metadata
with an attributelocale
having the valueen_US
in addition to the tables unique to your app.Subclassing
SQLiteOpenHelper
:SQLiteOpenHelper
.private
method within theSQLiteOpenHelper
subclass. This method contains the logic to copy database contents from the database file in the 'assets' folder to the database created in the application package context.onCreate
,onUpgrade
andonOpen
methods ofSQLiteOpenHelper
.Enough said. Here goes the
SQLiteOpenHelper
subclass:Finally, to get a database connection, just call
getReadableDatabase()
orgetWritableDatabase()
on theSQLiteOpenHelper
subclass and it will take care of creating a db, copying db contents from the specified file in the 'assets' folder, if the database does not exist.In short, you can use the
SQLiteOpenHelper
subclass to access the db shipped in the assets folder just as you would use for a database that is initialized using SQL queries in theonCreate()
method.