Android 备份/恢复:如何备份内部数据库?

问题描述:

我已经使用提供的 FileBackupHelper 实现了一个 BackupAgentHelper 来备份和恢复我拥有的本机数据库.这是您通常与 ContentProviders 一起使用的数据库,它位于 /data/data/yourpackage/databases/.

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/.

人们会认为这是一个常见的情况.但是文档并不清楚该怎么做:http://developer.android.com/guide/topics/data/backup.html.没有专门用于这些典型数据库的BackupHelper.因此,我使用了 FileBackupHelper,将其指向我在/databases/"中的 .db 文件,在任何 db 操作(例如 db.insert) 在我的 ContentProviders 中,甚至尝试在 onRestore() 之前创建/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.

我过去曾在不同的应用程序中成功地为 SharedPreferences 实施了类似的解决方案.但是,当我在 emulator-2.2 中测试我的新实现时,我看到正在从日志中对 LocalTransport 执行备份,以及正在执行的恢复(和 onRestore()> 叫).然而,db 文件本身从未被创建.

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.

请注意,这一切都是在安装之后、首次启动应用程序之前、执行恢复之后.除此之外,我的测试策略基于 http://developer.android.com/guide/topics/data/backup.html#Testing.

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.

另请注意,我不是在谈论我自己管理的一些 sqlite 数据库,也不是在谈论备份到 SD 卡、自己的服务器或其他地方.

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

我确实在文档中看到关于建议使用自定义 BackupAgent 的数据库的提及,但它似乎不相关:

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

但是,您可能想要扩展如果您需要,请直接 BackupAgent:* 备份数据库中的数据.如果您有一个 SQLite 数据库当用户想要恢复时重新安装您的应用程序,您需要构建一个自定义的 BackupAgent在一个过程中读取适当的数据备份操作,然后创建您的table 并在 a 期间插入数据恢复操作.

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.

请说清楚.

如果我真的需要自己做到SQL级别,那么我担心以下主题:

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.

如何在恢复时做同样的事情.据我了解,恢复可能会在用户已经开始使用应用程序(并将数据输入数据库)时发生.因此,您不能假定只是将备份的数据还原到位(删除空数据或旧数据).您必须以某种方式加入它,由于 id 的原因,这对于任何非平凡的数据库都是不可能的.

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.

更简洁的方法是创建自定义 BackupHelper:

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());
    }
}

然后将其添加到BackupAgentHelper:

public void onCreate() {
    addHelper(DATABASE, new DbBackupHelper(this, DB.FILE));
}