Illustration by Virginia Poltrack

Packing the Room: pre-populate your database with this one method

Florina Muntenescu
Android Developers

--

Let’s say that you want to pre-populate your database with data either packaged in your APK or downloaded from server. Whether you wanted to do this with SQLite or with Room, there are several things to handle: opening the database, validating the schema, locking the database file and handling thread synchronisation, copying all the contents and closing the database.

Starting with Room 2.2 (currently in alpha), you can pre-populate your database by calling one method: RoomDatabase.Builder#createFromAsset() or createFromFile(), depending on the location of your pre-packaged database. Read on to find out how to use these methods, some tips on working with pre-packaged databases and what happens when migration is involved.

createFromAsset()

If your pre-packaged database is part of your app’s assets/ folder, use createFromAsset() passing the asset’s path as a parameter. For example, if your database is located at: assets/database/myapp.db, you would pass “database/myapp.db”:

Room.databaseBuilder(appContext, TestDatabase.class, “Sample.db”)
.createFromAsset(“database/myapp.db”)
.build()

createFromFile()

If your database is not in the assets/ folder e.g. you downloaded it from a server and saved to disk, use createFromFile() and pass the File.

Room.databaseBuilder(appContext, TestDatabase.class, “Sample.db”)
.createFromFile(File(“mypath”))
.build()

🚫 In memory databases don’t support pre-populating the database via createFromAsset or createFromFile and RoomDatabase.build() method will throw an IllegalArgumentException if you try to do this.

File rights

Room doesn’t open the database you provide, instead it copies it. So, if you’re using a File, make sure you have read permissions, so Room can copy it.

Database validation

Room ensures the validity of the database when migrating from one version to another, so it applies the same validity checks when creating the database from assets or file. Like this, it ensures that the schemas of the databases you’re copying the data to and from match.

💡 Room allows exporting the database schema via the exportSchema parameter in the @Database annotation. So when you’re creating the pre-packaged database, use the schema defined there.

Database migrations

In general, when your database schema changes, you increase the database version in the @RoomDatabase annotation and either implement a migration or enable destructive migrations. Room will look at the version already installed on the device and the latest version defined in your app.

For example, let’s say that the database on the device is version 2 and your app’s database version, defined in @RoomDatabase, is 4. Here’s see what happens in different scenarios, when the pre-packaged database is also added in the mix:

1. Destructive migrations are enabled and the pre-packaged database has an older version than the one defined in your app, then database is dropped and data is not copied.

Example: If the pre-packaged database is version 3 and destructive migrations is enabled, then the database is dropped and data is not copied.

2. Destructive migrations are enabled and the pre-packaged database has the same version as the version defined in your app, then database is dropped and data is copied from the pre-packaged database.

Example: if the pre-packaged database is version 4, like the app’s database version, and destructive migrations is enabled, then the database is dropped and data is copied from the pre-packaged database.

3. A migration is implemented and the version of the pre-packaged database is older than the one in your @RoomDatabase annotation, then Room will copy the data and run the migrations.

Example: if the pre-packaged database is version 3 and you have the following migrations implemented: from version 2 to 3 and 3 to 4, then the migration from version 2 to 3 will be run, the database will be copied and then the migration from version 3 to 4 is run.

💡As a best practice, make sure that the pre-packaged database is the same version as the latest declared in the @RoomDatabase annotation. This way you avoid having to deal with migration cases.

📖 Read more about migrations in room in this blog post and about testing migrations here.

Now you can easily populate a Room database either from data shipped in your app or from a file. Room protects your data’s integrity and helps you to perform migrations when necessary. Let us know how you use pre-packaged databases in your app in the comments below!

Thanks to Daniel Santiago, Nick Butcher and Jose Alcérreca! 💚

--

--