Ich habe implementiert eine BackupAgentHelper
der vorgesehenen Verwendung FileBackupHelper
zu sichern und wiederherzustellen die native Datenbank ich habe. Dies ist die Datenbank, die Sie normalerweise zusammen mit der Datenbank verwenden ContentProviders
und in der Sie sich befinden /data/data/yourpackage/databases/
.
Man würde denken, dass dies ein häufiger Fall ist. In den Dokumenten ist jedoch nicht klar, was zu tun ist: http://developer.android.com/guide/topics/data/backup.html . Es gibt keine BackupHelper
speziell für diese typischen Datenbanken. Daher habe ich das verwendetFileBackupHelper
, auf meine .db-Datei in " /databases/
" verwiesen , Sperren für alle db-Operationen (wie z. B. db.insert
) in meinem eingeführt ContentProviders
und sogar versucht, das /databases/
Verzeichnis " " vorher zu erstellen, onRestore()
da es nach der Installation nicht vorhanden ist.
Ich habe SharedPreferences
in der Vergangenheit eine ähnliche Lösung für die erfolgreich in einer anderen App implementiert . Wenn ich jedoch meine neue Implementierung im Emulator-2.2 teste, wird eine Sicherung LocalTransport
aus den Protokollen sowie eine Wiederherstellung durchgeführt (und onRestore()
aufgerufen). Die Datenbankdatei selbst wird jedoch nie erstellt.
Beachten Sie, dass dies alles nach einer Installation und vor dem ersten Start der App, nachdem die Wiederherstellung durchgeführt wurde, erfolgt. Abgesehen davon basierte meine Teststrategie auf http://developer.android.com/guide/topics/data/backup.html#Testing .
Bitte beachten Sie auch, dass ich weder über eine von mir selbst verwaltete SQLite-Datenbank noch über das Sichern auf einer SD-Karte, einem eigenen Server oder anderswo spreche.
Ich habe in den Dokumenten eine Erwähnung von Datenbanken gesehen, die die Verwendung eines benutzerdefinierten Benutzers empfehlen, BackupAgent
aber es scheint nicht verwandt zu sein:
Möglicherweise möchten Sie BackupAgent jedoch direkt erweitern, wenn Sie: * Daten in einer Datenbank sichern müssen. Wenn Sie über eine SQLite-Datenbank verfügen, die Sie wiederherstellen möchten, wenn der Benutzer Ihre Anwendung erneut installiert, müssen Sie einen benutzerdefinierten BackupAgent erstellen, der die entsprechenden Daten während eines Sicherungsvorgangs liest. Erstellen Sie dann Ihre Tabelle und fügen Sie die Daten während eines Wiederherstellungsvorgangs ein.
Etwas Klarheit bitte.
Wenn ich es wirklich bis zur SQL-Ebene selbst tun muss, mache ich mir Sorgen um die folgenden Themen:
Öffnen Sie Datenbanken und Transaktionen. Ich habe keine Ahnung, wie ich sie aus einer solchen Singleton-Klasse außerhalb des Workflows meiner App schließen kann.
So benachrichtigen Sie den Benutzer, dass eine Sicherung ausgeführt wird und die Datenbank gesperrt ist. Es kann lange dauern, daher muss ich möglicherweise einen Fortschrittsbalken anzeigen.
So machen Sie dasselbe bei der Wiederherstellung. Soweit ich weiß, kann die Wiederherstellung nur dann erfolgen, wenn der Benutzer die App bereits verwendet hat (und Daten in die Datenbank eingibt). Sie können also nicht davon ausgehen, dass nur die Backupped-Daten wiederhergestellt werden (Löschen der leeren oder alten Daten). Sie müssen sich irgendwie daran beteiligen, was für jede nicht triviale Datenbank aufgrund der IDs unmöglich ist.
So aktualisieren Sie die App nach der Wiederherstellung, ohne dass der Benutzer an einem - jetzt - nicht erreichbaren Punkt hängen bleibt.
Kann ich sicher sein, dass die Datenbank beim Sichern oder Wiederherstellen bereits aktualisiert wurde? Andernfalls stimmt das erwartete Schema möglicherweise nicht überein.
Antworten:
Ein sauberer Ansatz wäre, eine benutzerdefinierte zu erstellen
BackupHelper
:und dann hinzufügen zu
BackupAgentHelper
:quelle
Nachdem ich meine Frage erneut geprüft hatte , konnte ich sie zum Laufen bringen, nachdem ich mir angesehen hatte, wie ConnectBot das macht . Danke Kenny und Jeffrey!
Es ist eigentlich so einfach wie das Hinzufügen:
zu deinem
BackupAgentHelper
.Der Punkt, den ich vermisst habe, war die Tatsache, dass Sie einen relativen Pfad mit "
../databases/
" verwenden müssten .Dies ist jedoch keineswegs eine perfekte Lösung. Die zu
FileBackupHelper
erwähnenden Dokumente zum Beispiel: "FileBackupHelper
sollten nur mit kleinen Konfigurationsdateien verwendet werden, nicht mit großen Binärdateien. " Letzteres ist bei SQLite-Datenbanken der Fall.Ich würde gerne mehr Vorschläge, Einblicke in das bekommen, was von uns erwartet wird (was die richtige Lösung ist) und Ratschläge, wie dies brechen könnte.
quelle
db.open()
durchdb.close()
oder nurinsert
Anweisungen synchronisieren muss oder was.Hier ist eine noch sauberere Möglichkeit, Datenbanken als Dateien zu sichern. Keine fest codierten Pfade.
Hinweis: getFilesDir wird überschrieben, sodass FileBackupHelper im Datenbankverzeichnis und nicht im Dateiverzeichnis funktioniert.
Ein weiterer Hinweis: Sie können auch databaseList verwenden , um alle Ihre DBs und Feed-Namen aus dieser Liste (ohne übergeordneten Pfad) in FileBackupHelper abzurufen. Dann würden alle DBs der App als Backup gespeichert.
quelle
Die Verwendung
FileBackupHelper
zum Sichern / Wiederherstellen von sqlite db wirft einige schwerwiegende Fragen auf:1. Was passiert, wenn die App den Cursor verwendet, der von abgerufen wurde,
ContentProvider.query()
und der Sicherungsagent versucht, die gesamte Datei zu überschreiben?2. Der Link ist ein schönes Beispiel für perfekte Tests (niedrige Entrophie;). Sie deinstallieren die App, installieren sie erneut und die Sicherung wird wiederhergestellt. Das Leben kann jedoch brutal sein. Schauen Sie sich den Link an . Stellen wir uns ein Szenario vor, in dem ein Benutzer ein neues Gerät kauft. Da es keinen eigenen Satz hat, verwendet der Sicherungsagent den Satz eines anderen Geräts. Die App ist installiert und Ihr backupHelper ruft alte Dateien mit einem Datenbankversionsschema ab, das niedriger als das aktuelle ist.
SQLiteOpenHelper
AufrufeonDowngrade
mit der Standardimplementierung:Unabhängig davon, was der Benutzer tut, kann er Ihre App auf dem neuen Gerät nicht verwenden.
Ich würde vorschlagen
ContentResolver
, Daten abzurufen -> serialisieren (ohne_id
s) zum Sichern und Deserialisieren -> Daten zum Wiederherstellen einfügen.Hinweis: Das Abrufen / Einfügen von Daten erfolgt über ContentResolver, wodurch Probleme mit der Cuncurrency vermieden werden. Die Serialisierung erfolgt in Ihrem backupAgent. Wenn Sie Ihre eigene Cursor-<-> Objektzuordnung ausführen, kann die Serialisierung eines Elements so einfach sein wie die Implementierung
Serializable
mit demtransient
Feld _id in der Klasse, die Ihre Entität darstellt.Ich würde auch Masseneinsatz dh verwende
ContentProviderOperation
Beispiel undCursorLoader.setUpdateThrottle
so , dass der App mit dem Neustart Loader nicht klemmt Prozess auf Datenänderung während der Sicherung wiederherstellen.Wenn Sie sich in einem Downgrade befinden, können Sie entweder die Wiederherstellungsdaten abbrechen oder ContentResolver mit Feldern wiederherstellen und aktualisieren, die für die herabgestufte Version relevant sind.
Ich bin damit einverstanden, dass das Thema nicht einfach ist, in Dokumenten nicht gut erklärt wird und einige Fragen wie die Größe von Massendaten usw. weiterhin bestehen.
Hoffe das hilft.
quelle
Ab Android M steht Apps nun eine vollständige Datensicherungs- / Wiederherstellungs-API zur Verfügung. Diese neue API enthält eine XML-basierte Spezifikation im App-Manifest, mit der der Entwickler beschreiben kann, welche Dateien direkt semantisch gesichert werden sollen: 'Sichern der Datenbank mit dem Namen "mydata.db"'. Diese neue API ist für Entwickler viel einfacher zu verwenden - Sie müssen keine Unterschiede nachverfolgen oder explizit einen Sicherungsdurchlauf anfordern, und die XML-Beschreibung der zu sichernden Dateien bedeutet, dass Sie häufig keinen Code schreiben müssen überhaupt.
(Sie können sich sogar an einer vollständigen Datensicherung / -wiederherstellung beteiligen, um beispielsweise beim Wiederherstellen einen Rückruf zu erhalten. Auf diese Weise ist dies flexibel.)
Finden Sie in der Konfiguration der automatischen Sicherung für Apps Abschnitt auf developer.android.com für eine Beschreibung, wie die neue API zu verwenden.
quelle
Eine Möglichkeit besteht darin, es in der Anwendungslogik über der Datenbank zu erstellen. Es schreit tatsächlich nach einem solchen Level, denke ich. Ich bin mir nicht sicher, ob Sie dies bereits tun, aber die meisten Leute (trotz des Cursor-Ansatzes von Android Content Manager) werden eine ORM-Zuordnung einführen - entweder eine benutzerdefinierte oder eine orm-lite-Methode. Und was ich in diesem Fall lieber tun würde, ist:
In diesem Fall also nicht auf DB-Ebene, sondern auf Anwendungsebene.
quelle