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

pjv*_*pjv 86 database android restore database-restore android-backup-service

我已经实现了BackupAgentHelper使用提供FileBackupHelper的备份和恢复我拥有的本机数据库.这是您通常与之一起使用ContentProviders并驻留在其中的数据库/data/data/yourpackage/databases/.

人们会认为这是一个常见的情况.但是,文档不清楚该怎么做:http://developer.android.com/guide/topics/data/backup.html.这些典型的数据库并不BackupHelper专门.因此,我使用了FileBackupHelper,将它指向我在."中的.db文件,在我的/databases/任何数据库操作(例如db.insert)中引入了锁ContentProviders,甚至尝试创建" /databases/"目录,onRestore()因为它在安装后不存在.

我已经SharedPreferences在过去的不同应用程序中成功实现了类似的解决方案.但是,当我在模拟器2.2中测试我的新实现时,我看到正在LocalTransport从日志执行备份,以及正在执行(并onRestore()调用)恢复.然而,db文件本身永远不会被创建.

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

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

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

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

请清楚一点.

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

  • 打开数据库和事务.我不知道如何在应用程序的工作流程之外从这样的单例类中关闭它们.

  • 如何通知用户正在进行备份并且数据库已锁定.这可能需要很长时间,所以我可能需要显示进度条.

  • 如何在恢复时执行相同操作.据我了解,恢复可能发生在用户已经开始使用应用程序(并将数据输入数据库)时.所以你不能假定只是恢复备份数据(删除空数据或旧数据).你必须以某种方式加入它,由于id的原因,任何非平凡的数据库都是不可能的.

  • 如何在恢复完成后刷新应用程序,而不会让用户卡在某个 - 现在 - 无法访问的点.

  • 我可以确定数据库是否已在备份或还原时升级?否则,预期的架构可能不匹配.

pjv*_*pjv 34

在重新审视我的问题之后,在查看ConnectBot的工作方式后,我能够让它工作.谢谢肯尼和杰弗里!

它实际上就像添加一样简单:

FileBackupHelper hosts = new FileBackupHelper(this,
    "../databases/" + HostDatabase.DB_NAME);
addHelper(HostDatabase.DB_NAME, hosts);
Run Code Online (Sandbox Code Playgroud)

到你的BackupAgentHelper.

我遗漏的一点是,你必须使用相对路径" ../databases/".

不过,这绝不是一个完美的解决方案.FileBackupHelper例如,提及的文档:" FileBackupHelper应仅用于小配置文件,而不是大型二进制文件. ",后者就是SQLite数据库的情况.

我想得到更多的建议,对我们的期望有什么见解(什么是正确的解决方案),以及如何解决这个问题的建议.

  • 硬编码路径是邪恶的. (6认同)

Poi*_*ull 22

这是将数据库备份为文件的更简洁方法.没有硬编码的路径.

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();
   }
}
Run Code Online (Sandbox Code Playgroud)

注意:它会覆盖getFilesDir,以便FileBackupHelper在数据库目录中工作,而不是文件目录.

另一个提示:您还可以使用databaseList将此列表中的所有数据库和提要名称(无父路径)提取到FileBackupHelper中.然后所有应用程序的数据库都将保存在备份中.


yan*_*nko 21

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

public class DbBackupHelper extends FileBackupHelper {

    public DbBackupHelper(Context ctx, String dbName) {
        super(ctx, ctx.getDatabasePath(dbName).getAbsolutePath());
    }
}
Run Code Online (Sandbox Code Playgroud)

然后将其添加到BackupAgentHelper:

public void onCreate() {
    addHelper(DATABASE, new DbBackupHelper(this, DB.FILE));
}
Run Code Online (Sandbox Code Playgroud)

  • **重要**:用于备份文件的(文档)(http://developer.android.com/guide/topics/data/backup.html#Files)表明操作不是线程安全**,所以您应该同步数据库方法和备份代理 (3认同)
  • @logray:该代码与问题中的代码完全相同.不必要的编辑. (2认同)

Pio*_*zan 7

使用FileBackupHelper备份/恢复的SQLite数据库提出了一些严肃的问题:
1,如果应用程序使用从检索到的光标会发生什么ContentProvider.query()和备份代理尝试重写整个文件?
这个链接是完美(低熵)测试的一个很好的例子.您卸载应用程序,再次安装它并恢复备份.然而,生活可能是残酷的.看看链接.让我们想象一下用户购买新设备的情况.由于它没有自己的设置,因此备份代理使用其他设备的设置.安装了该应用程序,您的backupHelper将检索db版本模式低于当前版本的旧文件.使用默认实现SQLiteOpenHelper调用onDowngrade:

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

无论用户做什么,他/她都无法在新设备上使用您的应用程序.

我建议使用ContentResolver获取数据 - >序列化(没有_ids)进行备份和反序列化 - >插入数据进行恢复.

注意:get/insert数据是通过ContentResolver完成的,从而避免了cuncurrency问题.序列化在backupAgent中完成.如果您自己创建游标< - >对象映射序列化项目可以像在表示您的实体的类上Serializable使用transient字段_id 一样简单.

我还使用批量插入即ContentProviderOperation 示例,CursorLoader.setUpdateThrottle以便应用程序在备份恢复过程中不会因重新启动加载程序而导致数据更改.

如果您确实处于降级状态,您可以选择中止还原数据,或者使用与降级版本相关的字段还原和更新ContentResolver.

我同意这个主题不容易,在文档中没有很好地解释,一些问题仍然像批量数据大小等.

希望这可以帮助.


cta*_*ate 5

从 Android M 开始,现在有一个可供应用程序使用的完整数据备份/恢复 API。这个新的 API 在应用程序清单中包含一个基于 XML 的规范,让开发人员可以直接语义方式描述要备份的文件:“备份名为“mydata.db”的数据库。这个新 API 对开发人员来说更容易使用——您不必跟踪差异或显式请求备份通过,并且要备份哪些文件的 XML 描述意味着您通常不需要编写任何代码根本。

(例如,您甚至可以参与完整数据备份/恢复操作以在恢复发生时获得回调。这种方式很灵活。)

有关如何使用新 API 的说明,请参阅developer.android.com 上的“为应用程序配置自动备份”部分。