Introduction
If your Android Application uses Room, then you might have wondered how to prepopulate a Room database. In this tutorial, we will learn how to prepopulate a Room database.
Goals
At the end of the tutorial, you would have learned:
- How to prepopulate a Room database.
Tools Required
- Android Studio. The version used in this tutorial is Bumblebee 2021.1.1 Patch 2.
Prerequisite Knowledge
- Basic Android.
- Basic Room.
Project Setup
To follow along with the tutorial, perform the steps below:
-
Create a new Android project with the default Empty Activity.
-
Add the dependencies below for Room into the Module build.gradle.
def room_version = "2.4.2" implementation "androidx.room:room-runtime:$room_version" kapt "androidx.room:room-compiler:$room_version" implementation "androidx.room:room-ktx:$room_version" implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
-
In the same file, add the kapt plugin under plugins.
id 'kotlin-kapt'
-
Add a new Person Entity with the code below.
@Entity(tableName = "person") data class Person( @PrimaryKey(autoGenerate = true) val id: Long, @ColumnInfo(name = "first_name") val firstName: String, @ColumnInfo(name = "last_name") val lastName: String )
-
Add a new Person DAO with the code below.
@Dao interface PersonDao { @Query("SELECT * FROM person WHERE id=:id") suspend fun getPersonById(id: Long): Person? }
-
Create a new Room database with the code below.
@Database(entities = [Person::class], version = 1) abstract class MyDatabase : RoomDatabase(){ abstract fun personDao(): PersonDao }
-
In MainActivity#
onCreate()
, append the code below. This creates a dummy connection to the database at launch so that we can have access to it in debug mode.val db = Room.databaseBuilder( applicationContext, MyDatabase::class.java, "my-database" ).build() lifecycleScope.launch { db.personDao().getPersonById(1) }
Project Overview
For this tutorial, we are not concerned about the UI at all and only focus on the Room database itself.
There is only one simple Student Entity in our App. At the end of the tutorial, we should be able to prepopulate our database with data on boot.
Options for prepopulating data
There are three different ways to prepopulate a database.
- The first option involves using prepackaged database files located under a special directory called
assets/
. - The second option allows you to load the prepackaged files from the file system itself.
- The third option includes loading the database files from an InputStream.
Because loading pre-packaged databases are all the same conceptually for all three options, we will only need to know how to do it with the assets/
resource directory. Loading a pre-packaged database from File or InputStream is only different depending on the location of the file.
All options require you to export your pre-built database, so we will learn how to do that first.
Export an Existing Database
To be able to export a database, we will need to build it first on a test device. Follow the steps below to create some data and export the database.
-
Select the top-most
app
directory of in the Android Project View. -
File > New > Folder > Assets Folder.
-
Start the App in Debug mode.
-
Open the App Inspection tab to start the Database Inspector.
-
Run the statement below to add some Person into the database.
INSERT INTO person VALUES (1, "Terence", "Landon"), (2, "Danielle", "Alger"), (3, "Arnold", "Chandler"), (4, "Mariah", "Blake"), (5, "Randal", " Maria ")
-
Now, highlight the
my-database
and select Export as File. Save it as a.db
file.
-
You can export directly into the assets directory created previously.
-
Optionally, save another copy of the same database as the
SQL
file extension, and then open the file with a text editor. With the human-readable SQL file, we now understand exactly which statements are run against the underlying SQLite database.PRAGMA foreign_keys=OFF; BEGIN TRANSACTION; CREATE TABLE android_metadata (locale TEXT); INSERT INTO android_metadata VALUES('en_US'); CREATE TABLE `person` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `first_name` TEXT NOT NULL, `last_name` TEXT NOT NULL); INSERT INTO person VALUES(1,'Terence','Landon'); INSERT INTO person VALUES(2,'Danielle','Alger'); INSERT INTO person VALUES(3,'Arnold','Chandler'); INSERT INTO person VALUES(4,'Mariah','Blake'); INSERT INTO person VALUES(5,'Randal',' Maria '); CREATE TABLE room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT); INSERT INTO room_master_table VALUES(42,'cd4ee16aca420ae15eab14b1baa5cdcf'); DELETE FROM sqlite_sequence; INSERT INTO sqlite_sequence VALUES('person',5); COMMIT;
Load prepackaged database from app Asset
Now that we have the exported database, it is quite simple to load it into our database on the first run. All we have to do is to call the function createFromAsset()
from the Room.Builder class on our database creation call. The builder step to add is:
.createFromAsset("my-database.db")
so that the previous database builder becomes this:
val db = Room.databaseBuilder(
applicationContext,
MyDatabase::class.java,
"my-database"
)
.createFromAsset("my-database.db")
.build()
If you reinstall the app, then you can see that the database now has data upon first boot.
Solution Code
MainActivity.kt
package com.codelab.daniwebandroidprepopulateroomdatabase
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import androidx.room.Room
import kotlinx.coroutines.launch
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db = Room.databaseBuilder(
applicationContext,
MyDatabase::class.java,
"my-database"
)
.createFromAsset("my-database.db")
.build()
lifecycleScope.launch {
db.personDao().getPersonById(1)
}
}
}
MyDatabase.kt
package com.codelab.daniwebandroidprepopulateroomdatabase
import androidx.room.Database
import androidx.room.RoomDatabase
@Database(entities = [Person::class], version = 1)
abstract class MyDatabase : RoomDatabase(){
abstract fun personDao(): PersonDao
}
Person.kt
package com.codelab.daniwebandroidprepopulateroomdatabase
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "person")
data class Person(
@PrimaryKey(autoGenerate = true) val id: Long,
@ColumnInfo(name = "first_name") val firstName: String,
@ColumnInfo(name = "last_name") val lastName: String
)
PersonDao
package com.codelab.daniwebandroidprepopulateroomdatabase
import androidx.room.Dao
import androidx.room.Query
@Dao
interface PersonDao {
@Query("SELECT * FROM person WHERE id=:id")
suspend fun getPersonById(id: Long): Person?
}
Module build.gradle
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'kotlin-kapt'
}
android {
compileSdk 32
defaultConfig {
applicationId "com.codelab.daniwebandroidprepopulateroomdatabase"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
def room_version = "2.4.2"
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.4.1'
implementation 'com.google.android.material:material:1.5.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
}
Summary
We have learned how to prepopulate a Room database in this tutorial. The full project code can be found at https://github.com/dmitrilc/DaniwebAndroidPrepopulateRoomDatabase