Room Database - Backup & Restore Features
Not that long ago I wanted to implement Backup & Restore features in my new application called Notably Notepad.
I thought such basic features will be well-documented and supported - I mean every app containing a database would want to allow the user to move his data to a new phone.
Yet again I was wrong, there is very little information about how to perform backup of Room Database and nothing in official android documentation.
The information that is available is incomplete, at least in my case, it wasn’t working - I had to compile information from many sources in order to get my code working.
Which why I wrote this article, hopefully someone will find it helpful.
Backup Database
In order for the backup feature to work as expected the following is necessary
- Database is created in Truncated journal mode
- Checkpoint query has been executed on the database
- Backup file has been saved on in shared storage
Database is created in Truncated journal mode
First thing that needs to be done is to create the database with appropriate journal mode.
Room.databaseBuilder(context, AppDatabase::class.java, name)
.setJournalMode(RoomDatabase.JournalMode.TRUNCATE)
.build()
When it comes to journal modes there are three options available:
JournalMode.AUTOMATIC
- default mode, Room will automatically choose journal modes based on the API and available device RAMJournalMode.TRUNCATE
- stores the database in one fileJournalMode.WRITE_AHEAD_LOGGING
- in this mode your database is stored inside two files - a database file and write ahead log file (database_name.wal) file making it impossible for you to back up your database to one file
It is important that the database is created with JournalMode.TRUNCATE
mode, since other modes might use two files for database storage - for user & implementation convenience it is much easier to work with one file.
Checkpoint query has been executed on the database
When the option to create a database backup is chosen by the user the following checkpoint query needs to be executed to ensure all of the pending transactions are applied.
For this a following method needs to be added to the database Dao
interface
interface UserDao {
@RawQuery
fun checkpoint(supportSQLiteQuery: SupportSQLiteQuery?): Single<Int>
}
Then the method needs to be called with the following SQL query
userDao.checkpoint((SimpleSQLiteQuery("pragma wal_checkpoint(full)")))
Once the checkpoint method has succeeded the database backup file can finally be saved.
Backup file has been saved on in shared storage
The database backup file can be retrieved using the following code
File(database.openHelper.writableDatabase.path)
The file then needs to be copied into the location picked by the user.
Restore Database
Now that the database is backed up to a file it is possible to restore it.
There are number of ways you can allow the user to pick the backup file (any file picker library, Storage Access Framework).
In my case Storage Access Framework was used
fun tryOpenFile() {
val intentType = "application/octet-stream"
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = intentType
putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(intentType))
}
activity.startActivityForResult(intent, OPEN_FILE_CODE)
}
The important part would be to set the intent type
and pass EXTRA_MIME_TYPES
to limit files visible by the user to those that are an application/octet-stream
, which is the type used for database files.
The last step is to replace the database file
File(database.openHelper.writableDatabase.path)
with the file that the user picked.
That’s all you need to add backup and restore features to your application!
In this article we have learned how to backup and restore Room database.
Resources: https://developer.android.com/guide/topics/providers/document-provider