87

BackupAgentHelper提供されているを使用して、所有しFileBackupHelperているネイティブデータベースをバックアップおよび復元するように実装しました。これは、通常一緒に使用するデータベースでContentProvidersあり、に存在し/data/data/yourpackage/databases/ます。

これは一般的なケースだと思うでしょう。ただし、ドキュメントでは何をすべきかが明確ではありません:http: //developer.android.com/guide/topics/data/backup.htmlこれらの典型的なデータベースには特にありません。BackupHelperしたがって、を使用しFileBackupHelper、 ""の.dbファイルをポイントし、/databases/のdb操作(などdb.insert)の周りにロックを導入し、インストール後に存在しないため、以前に""ディレクトリContentProvidersを作成しようとしました。/databases/onRestore()

SharedPreferences私は過去に別のアプリで成功するために同様のソリューションを実装しました。ただし、emulator-2.2で新しい実装をテストするとLocalTransport、ログからのバックアップが実行されていることと、復元が実行されている(およびonRestore()呼び出されている)ことがわかります。ただし、dbファイル自体は作成されません。

これはすべて、インストール後、アプリの最初の起動前、復元の実行後であることに注意してください。それとは別に、私のテスト戦略はhttp://developer.android.com/guide/topics/data/backup.html#Testingに基づいていました。

また、自分で管理しているsqliteデータベースについても、SDカードや独自のサーバーなどへのバックアップについても話していません。

カスタムを使用するようにアドバイスしているデータベースについての言及をドキュメントで見ましたBackupAgentが、それは関連していないようです:

ただし、次のことが必要な場合は、BackupAgentを直接拡張することをお勧めします。*データベース内のデータをバックアップします。ユーザーがアプリケーションを再インストールするときに復元するSQLiteデータベースがある場合は、バックアップ操作中に適切なデータを読み取るカスタムBackupAgentを構築し、テーブルを作成して復元操作中にデータを挿入する必要があります。

少し明確にしてください。

SQLレベルまで自分でそれを行う必要がある場合は、次のトピックについて心配しています。

  • データベースとトランザクションを開きます。アプリのワークフローの外で、このようなシングルトンクラスからそれらを閉じる方法がわかりません。

  • バックアップが進行中であり、データベースがロックされていることをユーザーに通知する方法。時間がかかる場合があるので、プログレスバーを表示する必要があるかもしれません。

  • 復元時に同じことを行う方法。私が理解しているように、復元は、ユーザーがすでにアプリの使用を開始したとき(およびデータベースにデータを入力したとき)に発生する可能性があります。したがって、バックアップされたデータを元の場所に復元する(空のデータまたは古いデータを削除する)とは限りません。どういうわけかそれに参加する必要がありますが、IDが原因で、重要なデータベースでは不可能です。

  • 復元が完了した後、ユーザーが到達不能な時点で立ち往生することなくアプリを更新する方法。

  • データベースがバックアップまたは復元時にすでにアップグレードされていることを確認できますか?そうしないと、期待されるスキーマが一致しない可能性があります。

4

6 に答える 6

34

私の質問を再検討した後、ConnectBotがどのように機能するかを確認した後、それを機能させることができました。ケニーとジェフリーに感謝します!

実際には、次を追加するのと同じくらい簡単です。

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

あなたにBackupAgentHelper

私が見逃していた点は、「../databases/」で相対パスを使用する必要があるという事実でした。

それでも、これは決して完璧な解決策ではありません。FileBackupHelperたとえば、言及するドキュメントは、 「FileBackupHelper大きなバイナリファイルではなく、小さな構成ファイルでのみ使用する必要があります。」、後者はSQLiteデータベースの場合です。

より多くの提案、私たちに期待されていること(適切な解決策は何か)についての洞察、およびこれがどのように壊れるかについてのアドバイスを取得したいと思います。

于 2011-06-13T15:08:35.067 に答える
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();
   }
}

注:これはgetFilesDirをオーバーライドて、FileBackupHelperがファイルdirではなくデータベースdirで機能するようにします。

別のヒント:databaseListを使用して、すべてのDBとフィード名をこのリスト(親パスなし)からFileBackupHelperに取得することもできます。次に、すべてのアプリのDBがバックアップに保存されます。

于 2012-03-15T11:21:37.450 に答える
21

よりクリーンなアプローチは、カスタムを作成することです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));
}
于 2012-03-31T14:35:08.640 に答える
8

FileBackupHelpersqlite dbのバックアップ/復元に使用すると、いくつかの深刻な問題
が発生します。1.アプリがから取得したカーソルを使用しContentProvider.query()、バックアップエージェントがファイル全体を上書きしようとするとどうなりますか?
2.リンクは、完璧な(低エントロピー;)テストの良い例です。アプリをアンインストールして再度インストールすると、バックアップが復元されます。しかし、人生は残酷なものになる可能性があります。リンクを見てください。ユーザーが新しいデバイスを購入するシナリオを想像してみましょう。独自のセットがないため、バックアップエージェントは他のデバイスのセットを使用します。アプリがインストールされ、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データの取得->バックアップ用のシリアル化(_idsなし)および逆シリアル化->復元用のデータの挿入に使用することをお勧めします。

注:データの取得/挿入はContentResolverを介して行われるため、cuncurrencyの問題を回避できます。シリアル化はbackupAgentで行われます。独自のカーソル<->オブジェクトマッピングを行う場合、アイテムのシリアル化は、エンティティを表すクラスにfield_idを使用して実装Serializableするのと同じくらい簡単です。transient

また、一括挿入、つまりContentProviderOperation CursorLoader.setUpdateThrottle使用して、バックアップの復元プロセス中にデータが変更されたときにアプリがローダーの再起動でスタックしないようにします。

ダウングレードの状況が発生した場合は、データの復元を中止するか、ダウングレードされたバージョンに関連するフィールドでContentResolverを復元および更新するかを選択できます。

私は、主題が簡単ではなく、ドキュメントで十分に説明されておらず、バルクデータサイズなどのいくつかの質問がまだ残っていることに同意します。

お役に立てれば。

于 2013-10-31T10:29:10.293 に答える
5

Android Mの時点で、アプリで利用できる完全なデータのバックアップ/復元APIがあります。この新しいAPIには、アプリマニフェストにXMLベースの仕様が含まれています。これにより、開発者は、バックアップするファイルを直接セマンティックな方法で記述できます。'「mydata.db」というデータベースをバックアップします。この新しいAPIは、開発者にとってはるかに使いやすくなっています。差分を追跡したり、バックアップパスを明示的に要求したりする必要はありません。また、バックアップするファイルのXML記述により、コードを記述する必要がないことがよくあります。まったく。

(たとえば、完全データのバックアップ/復元操作に参加して、復元が発生したときにコールバックを取得することもできます。そのように柔軟に対応できます。)

新しいAPIの使用方法の説明については、developer.android.comの「アプリの自動バックアップの構成」セクションを参照してください。

于 2015-12-27T04:39:13.400 に答える
0

1つのオプションは、データベースの上のアプリケーションロジックにビルドすることです。それは実際に私が思うそのようなlevellのために悲鳴を上げます。すでに行っているかどうかはわかりませんが、ほとんどの人は(Androidコンテンツマネージャーのカーソルアプローチにもかかわらず)、カスタムまたはorm-liteアプローチのいずれかのORMマッピングを導入します。そして、この場合、私がやりたいことは次のとおりです。

  1. アプリ/データがバックグラウンドで追加され、アプリケーションがすでに開始されている間に新しいデータが追加/削除されたときに、アプリケーションが正常に動作することを確認します
  2. Java-> protobufまたは単にJavaシリアル化マッピングを作成し、独自のBackupHelperを作成して、ストリームからデータを読み取り、データベースに追加するだけです。

したがって、この場合、dbレベルで実行するのではなく、アプリケーションレベルで実行します。

于 2011-06-19T20:37:51.220 に答える