Backup Room database
To more specifically answer your question, this is how I backup the room database in one of my Apps.
- Check for permission to read from / write to the external storage. You can ignore this step if you write to your App files directory.
- Close your
RoomDatabase
. In my caseAppDatabase
refers to a singleton that contains logic for building the room database initially.AppDatabase.getInstance(this).getDatabase()
gets the current instance of the singleton, and its current database class, that extends fromRoomDatabase
. This essentially callsRoomDatabase.close()
. - Define the source and destination files, depending on backing up or restoring. I include shm and wal files, even though they are temporary files.
- Copy the files with your method of choice.
FileUtils
in this case, refers tocommons-io
.
The code
if(id == R.id.action_save_db) {
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE);
if(permission == PackageManager.PERMISSION_GRANTED) {
AppDatabase.getInstance(this).getDatabase().close();
File db = getDatabasePath("my-db");
File dbShm = new File(db.getParent(), "my-db-shm");
File dbWal = new File(db.getParent(), "my-db-wal");
File db2 = new File("/sdcard/", "my-db");
File dbShm2 = new File(db2.getParent(), "my-db-shm");
File dbWal2 = new File(db2.getParent(), "my-db-wal");
try {
FileUtils.copyFile(db, db2);
FileUtils.copyFile(dbShm, dbShm2);
FileUtils.copyFile(dbWal, dbWal2);
} catch (Exception e) {
Log.e("SAVEDB", e.toString());
}
} else {
Snackbar.make(mDrawer, "Please allow access to your storage", Snackbar.LENGTH_LONG)
.setAction("Allow", view -> ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.WRITE_EXTERNAL_STORAGE
}, 0)).show();
}
} else if(id == R.id.action_load_db) {
int permission = ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE);
if(permission == PackageManager.PERMISSION_GRANTED) {
AppDatabase.getInstance(this).getDatabase().close();
File db = new File("/sdcard/", "my-db");
File dbShm = new File(db.getParent(), "my-db-shm");
File dbWal = new File(db.getParent(), "my-db-wal");
File db2 = getDatabasePath("my-db");
File dbShm2 = new File(db2.getParent(), "my-db-shm");
File dbWal2 = new File(db2.getParent(), "my-db-wal");
try {
FileUtils.copyFile(db, db2);
FileUtils.copyFile(dbShm, dbShm2);
FileUtils.copyFile(dbWal, dbWal2);
} catch (Exception e) {
Loge("RESTOREDB", e.toString());
}
} else {
Snackbar.make(mDrawer, "Please allow access to your storage", Snackbar.LENGTH_LONG)
.setAction("Allow", view -> ActivityCompat.requestPermissions(this, new String[] {
Manifest.permission.READ_EXTERNAL_STORAGE
}, 0)).show();
}
}
As an alternative, you can always create your Room database while forcing it not to use write ahead logging:
Room.databaseBuilder(context, db.class, dbName)
.setJournalMode(JournalMode.TRUNCATE)
.build();
This doesn't answer the original question
How can I properly re-open room db after I close it?
However, moving everything to the original database file is what you want to do, then you don't have to close the database in the first place. You can instead force a checkpoint using the wal_checkpoint
pragma.
Query the following statement against the database. We use raw queries here as pragma
is not yet supported by Room (it will trigger a UNKNOWN query type
error). Have this query inside of your DAO:
@RawQuery
int checkpoint(SupportSQLiteQuery supportSQLiteQuery);
And then when you call the checkpoint method, use the query then:
myDAO.checkpoint(new SimpleSQLiteQuery("pragma wal_checkpoint(full)"));
This link may shed some light on what wal_checkpoint
does.