Android backup / restore: how to back up the internal database?

I implemented BackupAgentHelper using the provided FileBackupHelper to backup and restore my own database, which I have. This is the database that you usually use with ContentProviders and which is located in /data/data/yourpackage/databases/ .

You might think that this is a common case. However, the docs are not clear what to do: http://developer.android.com/guide/topics/data/backup.html . For these typical databases, there is no BackupHelper . Therefore, I used FileBackupHelper , pointing it to my .db file in " /databases/ ", presented locks around any db operation (for example, db.insert ) in my ContentProviders and even tried to create " /databases/ " before onRestore() , because that it does not exist after installation.

I have implemented a similar solution for SharedPreferences successfully in another application in the past. However, when I test my new implementation in emulator-2.2, I see that the backup is being performed in LocalTransport from the logs, and the restore (and onRestore() ) is also running. However, the db file itself is never created.

Please note that this is all after installation and before the first launch of the application after recovery. In addition, my testing strategy was based on http://developer.android.com/guide/topics/data/backup.html#Testing .

Also note that I'm not talking about some sqlite database that I manage myself, nor about backing up to SDcard, my own server, or anywhere else.

I saw a mention in the docs on databases suggesting using a custom BackupAgent , but that doesn't seem like a link:

However, you can expand BackupAgent directly if you need to: * Back up data in a database. If you have a SQLite database, you want to restore when the user reinstalls your application, you need to create a custom BackupAgent that reads the corresponding data during the backup, then create tables and insert the data during recovery.

Some clarity please.

If I really need to do this on my own up to the SQL level, then the following topics concern me:

  • Open databases and transactions. I do not know how to close them from such a singleton class outside the workflow of my application.

  • How to notify the user that the backup is in progress and the database is locked. This can be time consuming, so I may need to show a progress bar.

  • How to do the same when recovering. As I understand it, recovery can only happen when the user has already started using the application (and enters data into the database). Therefore, you cannot just allow to restore backup data in place (deleting empty or old data). You will have to somehow join it, which is impossible for any non-trivial database because of the identifier.

  • How to update the application after recovery is complete, without forcing the user to get stuck in some now inaccessible point.

  • Can I be sure that the database has already been updated during backup or restore? Otherwise, the expected pattern may not match.

+82
android database restore android-backup-service
Mar 12 2018-11-12T00:
source share
6 answers

A cleaner approach would be to create a custom BackupHelper :

 public class DbBackupHelper extends FileBackupHelper { public DbBackupHelper(Context ctx, String dbName) { super(ctx, ctx.getDatabasePath(dbName).getAbsolutePath()); } } 

and then add it to BackupAgentHelper :

 public void onCreate() { addHelper(DATABASE, new DbBackupHelper(this, DB.FILE)); } 
+20
Mar 31 '12 at 14:35
source share

After revising my question, I was able to get it working after watching how ConnectBot does it . Thanks to Kenny and Jeffrey!

This is actually as simple as adding:

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

to your BackupAgentHelper .

What I was missing was that you would have to use the relative path with " ../databases/ ".

However, this is far from an ideal solution. For example, documents for FileBackupHelper are mentioned, for example: " FileBackupHelper should be used only with small configuration files, and not with large binary files." The latter applies to SQLite databases.

I would like to receive additional suggestions, to understand what is expected of us (what is the right decision) and advice on how this might break.

+33
Jun 13 '11 at 15:08
source share

Here's an even cleaner way to back up databases as files. There are no hard-coded 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 the dir directory and not in the dir files.

One more tip: you can also use databaseList to get all your DB names and feed from this list (without parent path) in FileBackupHelper. Then all application databases will be backed up.

+23
Mar 15 '12 at 11:21
source share

Using FileBackupHelper to backup / restore sqlite db raises a number of serious issues:
1. What happens if the application uses the cursor obtained from ContentProvider.query() and the backup agent tries to override the entire file?
2. Link is a good example of perfect testing (low entrophy;). You uninstall the application, install it again and restore the backup. However, life can be cruel. Check out the link . Imagine a scenario when a user buys a new device. Because it does not have its own set, the backup agent uses a different set of devices. The application is installed, and your backupHelper retrieves the old file with the db version scheme below the current one. SQLiteOpenHelper calls onDowngrade with the default implementation:

 public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { throw new SQLiteException("Can't downgrade database from version " + oldVersion + " to " + newVersion); } 

No matter what the user does, he / she cannot use your application on the new device.

I would suggest using ContentResolver to get data -> serialize (without _id s) for backup and deserialization -> insert data to restore.

Note. You can get / paste data using ContentResolver, thereby avoiding problems with the course. Serialization is performed on your BackupAgent. If you make your own cursor ↔ object matching, serializing an element can be as simple as implementing Serializable with the transient _id field in the class representing your entity.

I would also use a volume insert, i.e. ContentProviderOperation example and CursorLoader.setUpdateThrottle so that the application does not hang when the bootloader restarts changing data during backup recovery.

If you are faced with a downgrade situation, you can either refuse to restore the data, or restore and update the ContentResolver with fields related to the downgrade.

I agree that this question is not easy, implicitly explained in the documents, and some questions still remain the same as the volume size of the data, etc.

Hope this helps.

+7
Oct. 31 '13 at 10:29
source share

Starting with Android M, the full / backup / recovery API is now available for applications. This new API includes an XML-based specification in the application manifest, which allows the developer to describe which files should be executed in direct semantic mode: "back up the database called" mydata.db ". This new API is much easier for developers to use - you don’t need to explicitly track differences or request a backup pass, and the XML description for backing up files means you often don’t need to write any code at all.

(You can even participate in a backup and restore operation with a full amount of data to receive a callback, for example, when a restore occurs).

See Set up startup for apps on developer.android.com for a description of how to use the new API.

+3
Dec 27 '15 at 4:39 on
source share

One option is to build it in the application logic above the database. I think he actually screams about such a level. Not sure if you are already doing this, but most people (despite the approach of the android content management cursor) will introduce some kind of ORM display - both a user-defined and some kind of orm-lite approach. And in this case, I would prefer:

  • to make sure your application works fine when the application / data is added to the background with new data added / removed while the application is already running
  • do some java-> protobuf or even just java serialization mapping and own BackupHelper to read data from the stream and just add it to the database ....

So in this case, instead of doing it at the db level, do it at the application level.

0
Jun 19 2018-11-11T00:
source share



All Articles