How to use Room Persistence Library with pre-populated database?
AndroidAndroid SqliteAndroid RoomAndroid Room-PrepackageddatabaseAndroid Problem Overview
I'd like to use Room with a pre-populated database, but I can't understand how to tell Room where to find my database.
I've now put it in src/main/assets/databases
and when I create the instance for the Room database I create it this way:
Room.databaseBuilder(
getApplicationContext(),
AppDatabase.class,
"justintrain.db"
)
.allowMainThreadQueries()
.build();
This way tho, I think it's creating a new database every time, or anyways, it's not using the pre-populated one.
How can I make it to find my database?
Android Solutions
Solution 1 - Android
This is how I solved it, and how you can ship your application with a pre-populated database (up to Room v. alpha5)
-
put your SQLite DB
database_name.db
into theassets/databases
folder -
take the files from this repo and put them in a package called i.e.
sqlAsset
-
in your
AppDatabase
class, modify your Room's DB creation code accordingly:Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "database_name.db") .openHelperFactory(new AssetSQLiteOpenHelperFactory()) .allowMainThreadQueries() .build();
Note that you have to use "database_name.db"
and not getDatabasePath()
or other methods: it just needs the name of the file.
Solution 2 - Android
UPDATE (Nov 7th 2019)
Room now supports using a pre-packaged database out of the box, since version 2.2.0
https://developer.android.com/jetpack/androidx/releases/room#2.2.0
Solution before version 2.2.0: Simple solution without any other external libraries.
Room relies on the existing Android framework code to create or open a database. If you look into the source code of FrameworkSQLiteOpenHelper
(Room's version of SQLiteOpenHelper
) it internally calls SQLiteOpenHelper.getReadableDatabase()
and other methods wherever needed.
So, the simplest solution is to just copy the DB file from assets directory to mContext.getDatabasePath("my-database.sqlite")
before creating the DB with Room.
In your case, the code looks something like this -
private final String DB_NAME = "my-database.sqlite";
private MyDatabase buildDatabase(Context context) {
final File dbFile = context.getDatabasePath(DB_NAME);
if(!dbFile.exists()) {
copyDatabaseFile(dbFile.getAbsolutePath());
}
return Room.databaseBuilder(context.getApplicationContext(),
MyDatabase.class, DB_NAME)
.build();
}
private void copyDatabaseFile(String destinationPath) {
// code to copy the file from assets/database directory to destinationPath
}
This link has the code needed to copy the DB - link with code
Solution 3 - Android
I was having the same problem so I created a library which does exactly that. the accepted answer work but I think it's easier to use a library.
AppDatabase db = RoomAsset
.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "database_name.db")
.build();
Add it to your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url "https://jitpack.io" }
}
}
Add the dependency
dependencies {
// ... other dependencies
implementation 'com.github.humazed:RoomAsset:v1.0'
}
you can find the library here: https://github.com/humazed/RoomAsset
Solution 4 - Android
Working 2019 solution without hacks or dependencies (Kotlin)
-
Place your
.db
file inassets/databases
(or really any folder in there, as long as it's underassets
). -
Use Room 2.2's existing
createFromAsset()
function, passing in the path to the database. For example, if your database file is namedmy_data.db
and is under thedatabases
directory of theassets
folder, then you would docreateFromAsset("databases/my_data.db")
.
Assuming your database name (e.g., my_data
) is stored in a constant variable named DATABASE_NAME
, you can use this sample code:
Room.databaseBuilder(
context.applicationContext,
MyDatabase::class.java,
DATABASE_NAME
)
.createFromAsset("databases/$DATABASE_NAME.db")
.build()
Important: Make sure the schema of your data class/entity precisely matches the schema of your .db
file. For example, if a column isn't explicitly marked as NOT NULL
in the .db
file, then that means the column can have null
values in it. In Kotlin, you would have to match that with val colName: dataType? = null
in your data class. If you just do val colName: dataType
, Kotlin will compile that to a NOT NULL
column, and that will throw an exception when you try to run your app.
Note: If instead you want to create a Room database from a database file that you download onto the Android device itself, you can alternatively use the createFromFile()
function. Check out the official documentation on how to do this.
Solution 5 - Android
Room now supports Prepopulated Databases. Just prepare your database by using a program like SQLite Browser or any other of your choice. Then put it in Assets Folder
probably in a subfolder called database
then call:
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromAsset("database/myapp.db")
.build()
If you did not provide your database as an Asset but you downloaded it or it is in File System then then the method is:
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db")
.createFromFile(File("mypath"))
.build()
For more description or database migrations about this Feature you can check the Documentation Training.
Solution 6 - Android
Similar solution with room without using external libraries:
-
Copy your database in assets folder
-
Copy your database from assets folder
public class MainActivity extends AppCompatActivity {
public static AppDatabase db;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main);
copyDatabase(getApplicationContext(), "yourdatabase.db"); db = Room.databaseBuilder(getApplicationContext(), .class, "yourdatabase.db").allowMainThreadQueries().build();
}
private void copyDatabase(Context context, String databaseName) { final File dbPath = context.getDatabasePath(databaseName);
// If the database already exists, return if (dbPath.exists()) { Log.d("Activity", "db Path Exists"); return; } // Make sure we have a path to the file dbPath.getParentFile().mkdirs(); // Try to copy database file try { final InputStream inputStream = context.getAssets().open(databaseName); final OutputStream output = new FileOutputStream(dbPath); byte[] buffer = new byte[8192]; int length; while ((length = inputStream.read(buffer, 0, 8192)) > 0) { output.write(buffer, 0, length); } output.flush(); output.close(); inputStream.close(); } catch (IOException e) { Log.d("Activity", "Failed to open file", e); e.printStackTrace(); }
} }
Solution 7 - Android
Starting with Room 2.2, you can pre-populate your database using command below:
Room.databaseBuilder(appContext, TestDatabase.class, “Sample.db”)
.createFromAsset(“database/myapp.db”)
.build()
Solution 8 - Android
you just copy assets/databases
to app/databases
and than add addMigrations()
in databaseBuilder
it will keep your data