首页 文章

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

提问于
浏览
83

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

人们会认为这是一个常见的情况 . 但是,文档并不清楚该怎么做:http://developer.android.com/guide/topics/data/backup.html . There is no BackupHelper specifically for these typical databases. Hence I used the FileBackupHelper ,将它指向我的.db文件“ /databases/ ”,在我的 ContentProviders 中引入了围绕任何数据库操作(例如 db.insert )的锁,甚至尝试在 onRestore() 之前创建“ /databases/ ”目录,因为它在安装后不存在 .

我在过去的一个应用程序中成功地为 SharedPreferences 实现了类似的解决方案 . 但是,当我在模拟器2.2中测试我的新实现时,我看到从日志中执行了 LocalTransport 的备份,以及正在执行的恢复(以及 onRestore() 被调用) . Yet, the db file itself is never created.

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

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

我确实在文档中看到有关数据库建议使用自定义_1176659的提及,但它似乎没有关联:

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

Some clarity please.

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

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

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

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

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

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

6 回答

  • 33

    更简洁的方法是创建自定义 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));
    }
    
  • 7

    在重新审视我的问题之后,我能够在看完how ConnectBot does it之后开始工作 . 谢谢肯尼和杰弗里!

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

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

    到你的 BackupAgentHelper .

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

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

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

  • 21

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

    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来获取所有数据库's and feed names from this list (without parent path) into FileBackupHelper. Then all app'的数据库将保存在备份中 .

  • 0

    使用 FileBackupHelper 来备份/恢复sqlite db引发了一些严重的问题:
    1.如果应用程序使用从 ContentProvider.query() 检索的游标并且备份代理尝试覆盖整个文件,会发生什么?
    2. link是完美(低熵)测试的一个很好的例子 . 您卸载应用程序,再次安装它并恢复备份 . 然而,生活可能是残酷的 . 看看link . 设's imagine scenario when a user buys a new device. Since it doesn'有自己的设置,备份代理使用其他设备的设置 . 安装了该应用程序,您的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);
    }
    

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

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

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

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

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

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

    希望这可以帮助 .

  • 3

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

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

    有关如何使用新API的说明,请参阅developer.android.com上的Configuring Auto Backup for Apps部分 .

  • 23

    一种选择是在数据库上方的应用程序逻辑中构建它 . 我觉得它实际上是为了这样的事情而尖叫 . 不确定你是否已经这样做但是大多数人(尽管安卓内容管理器游标方法)将引入一些ORM映射 - 自定义或一些orm-lite方法 . 在这种情况下我宁愿做的是:

    • 以确保您的应用程序在后台添加应用程序/数据时正常工作,并在应用程序已启动时添加/删除新数据

    • 制作一些Java-> protobuf甚至简单的java序列化映射并编写自己的BackupHelper来从流中读取数据并简单地将其添加到数据库....

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

相关问题