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




restore database-restore android-backup-service (6)

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

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

  • 如何在还原完成后刷新应用程序,而不会让用户卡在某些 - 现在无法访问的点。

  • 我可以确定数据库在备份或恢复时已经升级了吗? 否则,预期的模式可能不匹配。


Answers

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

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

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

另一个提示是:您也可以使用databaseList将所有数据库和源名称从此列表(无父路径)中获取到FileBackupHelper中。 然后,所有应用程序的数据库将被保存在备份中。


一个更清晰的方法是创建一个自定义的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));
}

从Android M开始,现在有一个全数据备份/恢复API可用于应用程序。 这个新的API在应用清单中包含了一个基于XML的规范,它允许开发人员以直接语义的方式描述备份哪些文件:'备份名为“mydata.db”的数据库。 这个新的API对于开发者来说更​​容易使用 - 你不需要明确地跟踪差异或者请求备份传递,而且备份哪些文件的XML描述意味着你通常不需要编写任何代码在所有。

(例如,即使在全数据备份/恢复操作中,您可以参与恢复时发生的回调,这种方式非常灵活。)

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


使用FileBackupHelper备份/恢复sqlite数据库提出了一些严重的问题:
1.如果应用程序使用从ContentProvider.query()检索的游标并且备份代理尝试覆盖整个文件,会发生什么情况?
这个http://developer.android.com/guide/topics/data/backup.html#Testing是完美(低熵)测试的一个很好的例子。 您卸载应用程序,再次安装并且备份被恢复。 然而,生活可能是残酷的。 看看link 。 让我们来想象一下,用户购买新设备的场景。 由于它没有自己的集合,因此备份代理使用其他设备的集合。 该应用程序已安装,并且您的backupHelper将检索旧版本文件,其版本低于当前版本。 SQLiteOpenHelper使用默认实现调用onDowngrade

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

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

我建议使用ContentResolver获取数据 - >序列化(不带_id )备份和反序列化 - >插入数据进行还原。

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

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

如果您遇到降级情况,您可以选择中止还原数据,或者使用与降级版本相关的字段还原和更新ContentResolver。

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

希望这可以帮助。


一种选择是将其构建在数据库上方的应用程序逻辑中。 它实际上为我想的这样的levell尖叫。 不知道你是否已经这样做了,但大多数人(尽管android内容管理器光标方法)会引入一些ORM映射 - 无论是自定义还是一些orm-lite方法。 而我在这种情况下宁愿做的是:

  1. 以确保您的应用程序在应用程序/数据在后台添加时正常工作,并在应用程序启动时添加/删除新数据
  2. 制作一些Java-> protobuf甚至是简单的java序列化映射,并编写自己的BackupHelper以从流中读取数据并将其简单地添加到数据库中....

所以在这种情况下,而不是在数据库级别执行它在应用程序级别。


模拟器似乎在空闲时放慢速度。 通过快速将鼠标放在侧面的键上并观察点亮响应,可以明显看出这一点。 作为一种解决方法,我在启动模拟器时将-icount auto传递给QEMU 。 您可以创建一个名为my_avd.bat的批处理文件来为您执行此操作:

emulator @my_avd -no-boot-anim -qemu -icount auto
  • @my_avd - 启动名为“my_avd”的虚拟设备
  • -no-boot-anim - 禁用动画以加快启动速度
  • -qemu args... - 将参数传递给qemu
  • -icount [N|auto] - 启用虚拟指令计数器,每条指令有2 ^ N个时钟周期

这使动画黄油变得光滑,加速adb install十倍。





android database restore database-restore android-backup-service