Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android backup/restore: how to backup an internal database?

I have implemented a BackupAgentHelper using the provided FileBackupHelper to backup and restore the native database I have. This is the database you typically use along with ContentProviders and which resides in /data/data/yourpackage/databases/.

One would think this is a common case. However the docs aren't clear on what to do: http://developer.android.com/guide/topics/data/backup.html. There is no BackupHelper specifically for these typical databases. Hence I used the FileBackupHelper, pointed it to my .db file in "/databases/", introduced locks around any db operation (such as db.insert) in my ContentProviders, and even tried creating the "/databases/" directory before onRestore() because it does not exist after install.

I have implemented a similar solution for the SharedPreferences successfully in a different app in the past. However when I test my new implementation in the emulator-2.2, I see a backup being performed to LocalTransport from the logs, as well as a restore being performed (and onRestore() called). Yet, the db file itself is never created.

Note that this is all after an install, and before first launch of the app, after the restore has been performed. Apart from that my test strategy was based on http://developer.android.com/guide/topics/data/backup.html#Testing.

Please also note I'm not talking about some sqlite database I manage myself, nor about backing up to SDcard, own server or elsewhere.

I did see a mention in the docs about databases advising to use a custom BackupAgent but it does not seem related:

However, you might want to extend BackupAgent directly if you need to: * Back up data in a database. If you have an SQLite database that you want to restore when the user re-installs your application, you need to build a custom BackupAgent that reads the appropriate data during a backup operation, then create your table and insert the data during a restore operation.

Some clarity please.

If I really need to do it myself up to the SQL level, then I'm worried about the following topics:

  • Open databases and transactions. I have no idea how to close them from such a singleton class outside of my app's workflow.

  • How to notify the user that a backup is in progress and the database is locked. It might take a long time, so I might need to show a progress bar.

  • How to do the same on restore. As I understand, the restore might happen just when the user has already started using the app (and inputting data into the database). So you can't presume to just restore the backupped data in place (deleting the empty or old data). You'll have to somehow join it in, which for any non-trivial database is impossible due to the id's.

  • How to refresh the app after the restore is done without getting the user stuck at some - now - unreachable point.

  • Can I be sure the database has already been upgraded on backup or restore? Otherwise the expected schema might not match.

like image 800
pjv Avatar asked Mar 12 '11 13:03

pjv


People also ask

How do I Backup sqlite database on Android?

1. copy your db to sdcard 2. if reinstall, copy db back to the app. @earthw0rmjim Any approach in which I can get the original state retained without the network.


2 Answers

After revisiting my question, I was able to get it to work after looking at how ConnectBot does it. Thanks Kenny and Jeffrey!

It's actually as easy as adding:

FileBackupHelper hosts = new FileBackupHelper(this,     "../databases/" + HostDatabase.DB_NAME); addHelper(HostDatabase.DB_NAME, hosts); 

to your BackupAgentHelper.

The point I was missing was the fact that you'd have to use a relative path with "../databases/".

Still, this is by no means a perfect solution. The docs for FileBackupHelper mention for instance: "FileBackupHelper should be used only with small configuration files, not large binary files.", the latter being the case with SQLite databases.

I'd like to get more suggestions, insights into what is expected of us (what is the proper solution), and advice on how this might break.

like image 145
pjv Avatar answered Oct 12 '22 23:10

pjv


Here's yet cleaner way to backup databases as files. No hardcoded paths.

class MyBackupAgent extends BackupAgentHelper{    private static final String DB_NAME = "my_db";     @Override    public void onCreate(){       FileBackupHelper dbs = new FileBackupHelper(this, DB_NAME);       addHelper("dbs", dbs);    }     @Override    public File getFilesDir(){       File path = getDatabasePath(DB_NAME);       return path.getParentFile();    } } 

Note: it overrides getFilesDir so that FileBackupHelper works in databases dir, not files dir.

Another hint: you may also use databaseList to get all your DB's and feed names from this list (without parent path) into FileBackupHelper. Then all app's DB's would be saved in backup.

like image 45
Pointer Null Avatar answered Oct 12 '22 22:10

Pointer Null