Schlüssel/Wert-Paare mit dem Android Backup Service sichern

Android Backup Service bietet Cloud-Speicher-Back-up und Wiederherstellung für Schlüssel/Wert-Paare Daten in Ihrer Android-App. Während eines Schlüssel/Wert-Paar-Back-ups Daten an den Sicherungstransport des Geräts übergeben. Wenn auf dem Gerät der standardmäßige Google-Sicherungs-Transport verwendet wird, werden die Daten zur Archivierung an den Android-Sicherungsservice übergeben.

Die Daten sind auf 5 MB pro Nutzer Ihrer App beschränkt. Das Speichern ist kostenlos. Back-up-Daten.

Eine Übersicht über die Sicherungsoptionen von Android und Informationen dazu, welche Daten Sie sichern und wiederherstellen sollten, finden Sie im Hilfeartikel Datensicherung.

Schlüssel/Wert-Sicherung implementieren

Wenn Sie Ihre App-Daten sichern möchten, müssen Sie einen Sicherungsagenten implementieren. Der Sicherungsagent wird vom Sicherungsmanager sowohl bei der Sicherung als auch bei der Wiederherstellung aufgerufen.

Wenn Sie einen Sicherungsagenten implementieren möchten, müssen Sie Folgendes tun:

  1. Deklarieren Sie Ihren Sicherungsagenten in Ihrer Manifestdatei mit dem Attribut android:backupAgent.

  2. So definieren Sie einen Sicherungsagenten:

    • Erweiterung von BackupAgent

      Klasse BackupAgent stellt die zentrale Schnittstelle bereit, über die Ihre App mit dem Sicherungsmanager. Wenn Sie diese Klasse direkt erweitern, müssen Sie onBackup() und onRestore() überschreiben, um die Sicherungs- und Wiederherstellungsvorgänge für Ihre Daten zu verarbeiten.

    • BackupAgentHelper wird verlängert

      Die Klasse BackupAgentHelper ist ein praktischer Wrapper für die Klasse BackupAgent, wodurch die Menge des zu schreibenden Codes minimiert wird. In Ihrem BackupAgentHelper müssen Sie ein oder mehrere Hilfsobjekte verwenden, die bestimmte Datentypen automatisch sichern und wiederherstellen, damit Sie onBackup() und onRestore() nicht implementieren müssen. Es sei denn, Sie benötigen volle App-Sicherungen haben, empfehlen wir die Verwendung der BackupAgentHelper die Back-ups Ihrer App zu verwalten.

      Android bietet derzeit Sicherungshilfen, mit denen vollständige Dateien aus SharedPreferences und dem internen Speicher gesichert und wiederhergestellt werden können.

Deklarieren Sie den Sicherungsagenten in Ihrem Manifest.

Nachdem Sie sich für den Klassennamen Ihres Sicherungs-Agenten entschieden haben, deklarieren Sie ihn in Ihrem Manifest mit dem Attribut android:backupAgent im Tag <application>.

Beispiel:

<manifest ... >
    ...
    <application android:label="MyApplication"
                 android:backupAgent="MyBackupAgent">
        <meta-data android:name="com.google.android.backup.api_key"
            android:value="unused" />
        <activity ... >
            ...
        </activity>
    </application>
</manifest>

Zur Unterstützung älterer Geräte empfehlen wir, den API-Schlüssel <meta-data> hinzuzufügen in Ihre Android-Manifestdatei ein. Für den Android-Sicherungsservice ist kein Dienstschlüssel mehr erforderlich. Auf einigen älteren Geräten wird bei der Sicherung jedoch möglicherweise noch nach einem Schlüssel gesucht. Legen Sie android:name auf com.google.android.backup.api_key und android:value auf unused fest.

Die android:restoreAnyVersion verwendet einen booleschen Wert, um anzugeben, ob Sie die App wiederherstellen möchten Daten unabhängig von der aktuellen App-Version im Vergleich zur Version, die Backup-Daten erstellt haben. Der Standardwert ist false. Weitere Informationen finden Sie unter Version der wiederherzustellenden Daten prüfen.

BackupAgentHelper erweitern

Sie sollten Ihren Sicherungsagenten mit BackupAgentHelper erstellen, wenn Sie vollständige Dateien entweder aus SharedPreferences oder aus dem internen Speicher sichern möchten. Für die Erstellung eines Sicherungsagenten mit BackupAgentHelper ist viel weniger Code erforderlich als für die Erweiterung von BackupAgent, da Sie onBackup() und onRestore() nicht implementieren müssen.

Ihre Implementierung von BackupAgentHelper muss mindestens eine Sicherungshilfe verwenden. Ein Hilfsprogramm ist eine spezielle Komponente, die von BackupAgentHelper beschwört wird Sicherungs- und Wiederherstellungsvorgänge für einen bestimmten Datentyp ausführen. Das Android-Framework bietet derzeit zwei verschiedene Helfer:

Du kannst in deinem BackupAgentHelper mehrere Helfer hinzufügen, jedoch nur eine Hilfsprogramm für jeden Datentyp benötigt. Wenn Sie also mehrere SharedPreferences-Dateien haben, benötigen Sie nur eine SharedPreferencesBackupHelper.

Führen Sie für jeden Helfer, den Sie BackupAgentHelper hinzufügen möchten, die folgenden Schritte aus: folgen während des Methode onCreate():

  1. Instanziieren Sie eine Instanz der gewünschten Hilfsklasse. Im Klassenkonstruktor müssen Sie die Dateien angeben, die Sie sichern möchten.
  2. Rufen Sie addHelper() an, um den Helfer zu Ihrem BackupAgentHelper hinzuzufügen.

In den folgenden Abschnitten wird beschrieben, wie Sie mit den einzelnen verfügbaren Helfern.

SharedPreferences sichern

Wenn Sie eine SharedPreferencesBackupHelper-Instanz erstellen, müssen Sie den Namen einer oder mehrerer SharedPreferences-Dateien angeben.

Um beispielsweise eine SharedPreferences-Datei namens user_preferences zu sichern, Backup-Agent mit BackupAgentHelper abschließen sieht so aus:

Kotlin

// The name of the SharedPreferences file
const val PREFS = "user_preferences"

// A key to uniquely identify the set of backup data
const val PREFS_BACKUP_KEY = "prefs"

class MyPrefsBackupAgent : BackupAgentHelper() {
    override fun onCreate() {
        // Allocate a helper and add it to the backup agent
        SharedPreferencesBackupHelper(this, PREFS).also {
            addHelper(PREFS_BACKUP_KEY, it)
        }
    }
}

Java

public class MyPrefsBackupAgent extends BackupAgentHelper {
    // The name of the SharedPreferences file
    static final String PREFS = "user_preferences";

    // A key to uniquely identify the set of backup data
    static final String PREFS_BACKUP_KEY = "prefs";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        SharedPreferencesBackupHelper helper =
                new SharedPreferencesBackupHelper(this, PREFS);
        addHelper(PREFS_BACKUP_KEY, helper);
    }
}

Die SharedPreferencesBackupHelper enthält den gesamten Code, der zum Sichern und Wiederherstellen einer SharedPreferences-Datei erforderlich ist.

Wenn der Sicherungsmanager onBackup() und onRestore() aufruft, ruft BackupAgentHelper Ihre Sicherungshilfen auf, um die angegebenen Dateien zu sichern und wiederherzustellen.

Andere Dateien sichern

Wenn Sie eine FileBackupHelper-Instanz erstellen, müssen Sie den Namen einer oder mehrerer Dateien angeben, die gemäß getFilesDir() im internen Speicher Ihrer App gespeichert werden. Das ist derselbe Speicherort, an dem openFileOutput() Dateien schreibt.

Um beispielsweise zwei Dateien mit den Namen scores und stats zu sichern, einen Sicherungs-Agent mit BackupAgentHelper sieht so aus:

Kotlin

// The name of the file
const val TOP_SCORES = "scores"
const val PLAYER_STATS = "stats"
// A key to uniquely identify the set of backup data
const val FILES_BACKUP_KEY = "myfiles"

class MyFileBackupAgent : BackupAgentHelper() {
    override fun onCreate() {
        // Allocate a helper and add it to the backup agent
        FileBackupHelper(this, TOP_SCORES, PLAYER_STATS).also {
            addHelper(FILES_BACKUP_KEY, it)
        }
    }
}

Java

public class MyFileBackupAgent extends BackupAgentHelper {
    // The name of the file
    static final String TOP_SCORES = "scores";
    static final String PLAYER_STATS = "stats";

    // A key to uniquely identify the set of backup data
    static final String FILES_BACKUP_KEY = "myfiles";

    // Allocate a helper and add it to the backup agent
    @Override
    public void onCreate() {
        FileBackupHelper helper = new FileBackupHelper(this,
                TOP_SCORES, PLAYER_STATS);
        addHelper(FILES_BACKUP_KEY, helper);
    }
}

FileBackupHelper enthält den gesamten Code, der zum Sichern und Wiederherstellen -Dateien, die im internen Speicher der App gespeichert werden.

Das Lesen und Schreiben von Dateien im internen Speicher ist jedoch nicht Thread-sicher. Damit Ihr Sicherungs-Agent Ihre Daten nicht liest oder schreibt, und Ihre Aktivitäten verwenden, müssen Sie synchronisierte Anweisungen verwenden. jedes Mal, wenn Sie einen Lese- oder Schreibvorgang ausführen. Bei jeder Aktivität, bei der Sie zum Lesen und Schreiben der Datei benötigen, benötigen Sie ein Objekt, das Sie als intrinsische Sperre für den synchronisierten Anweisungen:

Kotlin

// Object for intrinsic lock
companion object {
    val sDataLock = Any()
}

Java

// Object for intrinsic lock
static final Object sDataLock = new Object();

Erstellen Sie dann bei jedem Lese- oder Schreibvorgang eine synchronisierte Anweisung mit dieser Sperre. die Dateien. Hier ist als Beispiel eine synchronisierte Anweisung zum Schreiben der aktuellen Punkte in einem Spiel in eine Datei hochladen:

Kotlin

try {
    synchronized(MyActivity.sDataLock) {
        val dataFile = File(filesDir, TOP_SCORES)
        RandomAccessFile(dataFile, "rw").apply {
            writeInt(score)
        }
    }
} catch (e: IOException) {
    Log.e(TAG, "Unable to write to file")
}

Java

try {
    synchronized (MyActivity.sDataLock) {
        File dataFile = new File(getFilesDir(), TOP_SCORES);
        RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
        raFile.writeInt(score);
    }
} catch (IOException e) {
    Log.e(TAG, "Unable to write to file");
}

Sie sollten Ihre Leseanweisungen mit derselben Sperre synchronisieren.

Anschließend müssen Sie in BackupAgentHelper onBackup() und onRestore() überschreiben, um die Sicherungs- und Wiederherstellungsvorgänge mit derselben intrinsischen Sperre zu synchronisieren. Für das Beispiel MyFileBackupAgent oben sind beispielsweise die folgenden Methoden erforderlich:

Kotlin

@Throws(IOException::class)
override fun onBackup(
        oldState: ParcelFileDescriptor,
        data: BackupDataOutput,
        newState: ParcelFileDescriptor
) {
    // Hold the lock while the FileBackupHelper performs back up
    synchronized(MyActivity.sDataLock) {
        super.onBackup(oldState, data, newState)
    }
}

@Throws(IOException::class)
override fun onRestore(
        data: BackupDataInput,
        appVersionCode: Int,
        newState: ParcelFileDescriptor
) {
    // Hold the lock while the FileBackupHelper restores the file
    synchronized(MyActivity.sDataLock) {
        super.onRestore(data, appVersionCode, newState)
    }
}

Java

@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
          ParcelFileDescriptor newState) throws IOException {
    // Hold the lock while the FileBackupHelper performs back up
    synchronized (MyActivity.sDataLock) {
        super.onBackup(oldState, data, newState);
    }
}

@Override
public void onRestore(BackupDataInput data, int appVersionCode,
        ParcelFileDescriptor newState) throws IOException {
    // Hold the lock while the FileBackupHelper restores the file
    synchronized (MyActivity.sDataLock) {
        super.onRestore(data, appVersionCode, newState);
    }
}

BackupAgent erweitern

Bei den meisten Apps ist es nicht erforderlich, die Klasse BackupAgent direkt zu erweitern. Stattdessen sollten Sie BackupAgentHelper erweitern, um die integrierten Hilfsklassen zu nutzen, mit denen Ihre Dateien automatisch gesichert und wiederhergestellt werden. Sie können BackupAgent jedoch direkt erweitern, um Folgendes zu tun:

  • Versionieren Sie Ihr Datenformat. Wenn Sie beispielsweise davon ausgehen, dass Sie das Format, in dem Sie Ihre App-Daten schreiben, überarbeiten müssen, können Sie einen Sicherungsagenten erstellen, der Ihre App-Version während eines Wiederherstellungsvorgangs prüft und alle erforderlichen Kompatibilitätsarbeiten ausführt, wenn sich die Version auf dem Gerät von der der Sicherungsdaten unterscheidet. Weitere Informationen finden Sie unter Die Wiederherstellung überprüfen. Datenversion.
  • Geben Sie an, welche Daten gesichert werden sollen. Anstatt eine ganze Datei zu sichern, können Sie angeben, welche Daten gesichert werden sollen und wie jeder Teil dann auf dem Gerät wiederhergestellt wird. Dies kann Ihnen auch dabei helfen, verschiedene Versionen, da Sie Ihre Daten als eindeutige Entitäten lesen und schreiben als vollständige Dateien.
  • Daten in einer Datenbank sichern Wenn Sie eine SQLite-Datenbank haben, die Sie wiederherstellen möchten, wenn der Nutzer Ihre App neu installiert, müssen Sie eine benutzerdefinierte BackupAgent erstellen, die die entsprechenden Daten während eines Sicherungsvorgangs liest, dann die Tabelle erstellt und die Daten während eines Wiederherstellungsvorgangs einfügt.

Wenn Sie keine der oben genannten Aufgaben ausführen müssen und vollständige Dateien aus SharedPreferences oder dem internen Speicher sichern möchten, lesen Sie den Hilfeartikel BackupAgentHelper erweitern.

Erforderliche Methoden

Wenn Sie eine BackupAgent erstellen, müssen Sie die folgenden Rückrufmethoden implementieren:

onBackup()
Der Backup Manager ruft diese Methode auf, nachdem Sie eine Back-up. Bei dieser Methode lesen Sie Ihre App-Daten aus dem und die zu sichernden Daten an den Backup Manager übergeben, wie unter Daten auf einem Pixel sichern oder wiederherstellen beschrieben.
onRestore()

Der Sicherungsmanager ruft diese Methode während eines Wiederherstellungsvorgangs auf. Bei dieser Methode werden Ihre Sicherungsdaten bereitgestellt, mit denen Ihre App ihren vorherigen Zustand wiederherstellen kann, wie unter Wiederherstellung ausführen beschrieben.

Das System ruft diese Methode auf, um Sicherungsdaten wiederherzustellen, wenn der Nutzer Ihre App neu installiert. Ihre App kann aber auch eine Wiederherstellung anfordern.

Sicherung durchführen

Eine Sicherungsanfrage führt nicht zu einem sofortigen Aufruf deiner onBackup()-Methode. Stattdessen wartet der Sicherungsmanager auf einen angemessenen Zeitraum und dann führt eine Sicherung für alle Apps aus, die seit der letzten Sicherung durchgeführt. An dieser Stelle müssen Sie Ihre App-Daten an den Sicherungsmanager weitergeben, damit sie im Cloud-Speicher gespeichert werden können.

Nur der Sicherungsmanager kann die onBackup()-Methode Ihres Sicherungsagenten aufrufen. Jedes Mal, wenn sich Ihre App-Daten ändern und Sie eine Sicherung durchführen möchten, müssen Sie einen Sicherungsvorgang anfordern, indem Sie dataChanged() aufrufen. Weitere Informationen finden Sie unter Sicherung anfordern.

Tipp: Während der Entwicklung Ihrer App können Sie sofort eine Sicherung starten. über den Sicherungsmanager mit der bmgr .

Wenn der Sicherungsmanager die Methode onBackup() aufruft, werden drei Parameter:

oldState
Offene, schreibgeschützte Datei ParcelFileDescriptor, der zeigt in den letzten von Ihrer App bereitgestellten Sicherungsstatus. Dies sind nicht die Sicherungsdaten aus einem Cloud-Speicher, sondern eine lokale Darstellung der gesicherten Daten. Zeitpunkt, zu dem onBackup() zuletzt aufgerufen wurde (definiert durch newState oder von onRestore() onRestore() wird im nächsten Abschnitt behandelt. Weil onBackup() lässt das Lesen vorhandener Sicherungsdaten in der Cloud nicht zu Speicher verwenden, können Sie anhand dieser lokalen Darstellung feststellen, sich seit der letzten Sicherung geändert hat.
data
Ein BackupDataOutput Objekt, mit dem Sie Ihre Sicherungsdaten an den Sicherungsmanager senden.
newState
Ein offener, nicht schreibgeschützter ParcelFileDescriptor, der auf eine Datei verweist, in der Sie muss eine Darstellung der Daten schreiben, die Sie an data gesendet haben. A kann die Darstellung ganz einfach sein, zum Beispiel der Zeitstempel der letzten Änderung für Ihre Datei. Dieses Objekt wird als oldState zurückgegeben, wenn Backup Manager das nächste Mal aufruft. Ihre onBackup()-Methode. Wenn Sie Ihre Sicherungsdaten nicht in newState schreiben, verweist oldState das nächste Mal auf eine leere Datei, wenn Backup Manager das nächste Mal aufruft onBackup()

Implementieren Sie mithilfe dieser Parameter die Methode onBackup(), um Folgendes zu tun:

  1. Prüfen Sie, ob sich Ihre Daten seit der letzten Sicherung geändert haben, indem Sie oldState zu Ihren aktuellen Daten. Wie Sie Daten in oldState lesen, hängt davon ab, wie Sie sie ursprünglich in newState geschrieben haben (siehe Schritt 3). Am einfachsten lässt sich der Status einer Datei mit dem Zeitstempel der letzten Änderung erfassen. Beispiel: So kannst du einen Zeitstempel von oldState lesen und vergleichen:

    Kotlin

    val instream = FileInputStream(oldState.fileDescriptor)
    val dataInputStream = DataInputStream(instream)
    try {
       // Get the last modified timestamp from the state file and data file
       val stateModified = dataInputStream.readLong()
       val fileModified: Long = dataFile.lastModified()
       if (stateModified != fileModified) {
           // The file has been modified, so do a backup
           // Or the time on the device changed, so be safe and do a backup
       } else {
           // Don't back up because the file hasn't changed
           return
       }
    } catch (e: IOException) {
       // Unable to read state file... be safe and do a backup
    }

    Java

    // Get the oldState input stream
    FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
    DataInputStream in = new DataInputStream(instream);
    
    try {
       // Get the last modified timestamp from the state file and data file
       long stateModified = in.readLong();
       long fileModified = dataFile.lastModified();
    
       if (stateModified != fileModified) {
           // The file has been modified, so do a backup
           // Or the time on the device changed, so be safe and do a backup
       } else {
           // Don't back up because the file hasn't changed
           return;
       }
    } catch (IOException e) {
       // Unable to read state file... be safe and do a backup
    }

    Wenn sich nichts geändert hat und Sie keine Sicherung benötigen, fahren Sie mit Schritt 3 fort.

  2. Wenn sich Ihre Daten im Vergleich zu oldState geändert haben, schreiben Sie die aktuellen Daten in data, um sie im Cloud-Speicher zu sichern.

    Sie müssen jeden Datenblock als Entität in den BackupDataOutput schreiben. Eine entity ist ein vereinfachter binärer Datensatz, der durch einen eindeutigen Schlüssel identifiziert wird. . Der von Ihnen gesicherte Datensatz besteht also aus einer Reihe von Schlüssel/Wert-Paaren.

    So fügen Sie Ihrem Sicherungs-Dataset eine Entität hinzu:

    1. Anruf writeEntityHeader(), und übergeben einen eindeutigen Zeichenfolgenschlüssel für die Daten, die Sie schreiben möchten, und den der Datengröße.

    2. Rufen Sie writeEntityData() auf und übergeben Sie einen Byte-Puffer mit Ihren Daten und der Anzahl der Bytes, die aus dem Puffer geschrieben werden sollen. Diese Anzahl sollte der an writeEntityHeader() übergebenen Größe entsprechen.

    Im folgenden Code werden beispielsweise einige Daten in einen Bytestream flachgelegt und in eine einzelne Entität geschrieben:

    Kotlin

    val buffer: ByteArray = ByteArrayOutputStream().run {
       DataOutputStream(this).apply {
           writeInt(playerName)
           writeInt(playerScore)
       }
       toByteArray()
    }
    val len: Int = buffer.size
    data.apply {
       writeEntityHeader(TOPSCORE_BACKUP_KEY, len)
       writeEntityData(buffer, len)
    }

    Java

    // Create buffer stream and data output stream for our data
    ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
    DataOutputStream outWriter = new DataOutputStream(bufStream);
    // Write structured data
    outWriter.writeUTF(playerName);
    outWriter.writeInt(playerScore);
    // Send the data to the Backup Manager via the BackupDataOutput
    byte[] buffer = bufStream.toByteArray();
    int len = buffer.length;
    data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
    data.writeEntityData(buffer, len);

    Führen Sie diese Schritte für alle Datenelemente aus, die Sie sichern möchten. Wie Sie Ihre Daten in Entitäten unterteilen, bleibt Ihnen überlassen. Sie können auch nur eine Entität verwenden.

  3. Unabhängig davon, ob Sie eine Sicherung durchführen (in Schritt 2), schreiben Sie eine Darstellung die aktuellen Daten für newState ParcelFileDescriptor. Der Sicherungsmanager speichert dieses Objekt lokal als Darstellung der Daten, die gerade gesichert werden. Dieser Wert wird Ihnen beim nächsten Aufruf von onBackup() als oldState zurückgegeben, damit Sie feststellen können, ob eine weitere Sicherung erforderlich ist, wie in Schritt 1 beschrieben. Wenn Sie den aktuellen Datenstatus nicht in diese Datei schreiben, ist oldState beim nächsten Rückruf leer.

    Im folgenden Beispiel wird eine Darstellung der aktuellen Daten newState mit dem Zeitstempel der letzten Änderung der Datei:

    Kotlin

    val modified = dataFile.lastModified()
    FileOutputStream(newState.fileDescriptor).also {
       DataOutputStream(it).apply {
           writeLong(modified)
       }
    }

    Java

    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    DataOutputStream out = new DataOutputStream(outstream);
    
    long modified = dataFile.lastModified();
    out.writeLong(modified);

Wiederherstellung ausführen

Wenn es an der Zeit ist, Ihre App-Daten wiederherzustellen, ruft der Sicherungsmanager die onRestore()-Methode Ihres Sicherungsagenten auf. Wenn diese Methode aufgerufen wird, stellt der Sicherungsmanager Ihre Sicherungsdaten bereit, damit Sie sie auf dem Gerät wiederherstellen können.

Nur der Sicherungsmanager kann onRestore() aufrufen. Das geschieht automatisch, wenn das System Ihre App installiert und vorhandene Sicherungsdaten findet.

Wenn der Sicherungsmanager die Methode onRestore() aufruft, werden drei Parameter:

data
Ein BackupDataInput-Objekt, mit dem Sie Ihre Sicherungsdaten lesen können.
appVersionCode
Eine Ganzzahl, die den Wert der Methode android:versionCode Manifest-Attribut so wie es war, als diese Daten gesichert wurden. So können Sie die aktuelle App-Version prüfen und feststellen, ob das Datenformat kompatibel ist. Weitere Informationen zur Verwendung dieser Funktion zum Umgang mit verschiedenen Versionen von Wiederherstellungsdaten finden Sie unter Version der Wiederherstellungsdaten prüfen.
newState
Eine offene, lese-/schreibbare ParcelFileDescriptor, die auf eine Datei verweist, in die Sie den endgültigen Sicherungsstatus schreiben müssen, der mit data bereitgestellt wurde. Dieses Objekt wird beim nächsten Aufruf von onBackup() als oldState zurückgegeben. Wie du weißt, musst du dasselbe newState-Objekt auch im onBackup()-Callback schreiben. Wenn du das hier tust, ist das oldState-Objekt, das an onBackup() übergeben wird, auch beim ersten Aufruf von onBackup() nach der Wiederherstellung des Geräts gültig.

Bei der Implementierung von onRestore() sollten Sie Folgendes aufrufen: readNextHeader() zu data, um alle Entitäten im Dataset zu iterieren. Gehen Sie für jede gefundene Entität so vor:

  1. Rufen Sie den Entitätsschlüssel mit getKey() ab.
  2. Vergleichen Sie den Entitätsschlüssel mit einer Liste bekannter Schlüssel/Wert-Paare, die Sie haben sollten. als statische finale Strings in Ihrer BackupAgent-Klasse deklariert. Wenn der Parameter key mit einem Ihrer bekannten Schlüsselstrings übereinstimmt, geben Sie eine Anweisung ein, um und speichern Sie sie auf dem Gerät:

    1. Entitätsdatengröße abrufen mit getDataSize() und erstellen ein Byte-Array dieser Größe.
    2. Rufen Sie readEntityData() auf und übergeben Sie ihm das Byte-Array, in das die Daten gespeichert werden sollen. Geben Sie außerdem den Start-Offset und die Größe an, die gelesen werden soll.
    3. Dein Byte-Array ist jetzt voll. Sie können die Daten beliebig lesen und auf das Gerät schreiben.
  3. Nachdem Sie Ihre Daten auf das Gerät gelesen und geschrieben haben, schreiben Sie den Status Ihre Daten in den newState-Parameter, wie bei onBackup().

So können Sie beispielsweise die Daten wiederherstellen, die durch das Beispiel in im vorherigen Abschnitt:

Kotlin

@Throws(IOException::class)
override fun onRestore(data: BackupDataInput, appVersionCode: Int,
                       newState: ParcelFileDescriptor) {
    with(data) {
        // There should be only one entity, but the safest
        // way to consume it is using a while loop
        while (readNextHeader()) {
            when(key) {
                TOPSCORE_BACKUP_KEY -> {
                    val dataBuf = ByteArray(dataSize).also {
                        readEntityData(it, 0, dataSize)
                    }
                    ByteArrayInputStream(dataBuf).also {
                        DataInputStream(it).apply {
                            // Read the player name and score from the backup data
                            playerName = readUTF()
                            playerScore = readInt()
                        }
                        // Record the score on the device (to a file or something)
                        recordScore(playerName, playerScore)
                    }
                }
                else -> skipEntityData()
            }
        }
    }

    // Finally, write to the state blob (newState) that describes the restored data
    FileOutputStream(newState.fileDescriptor).also {
        DataOutputStream(it).apply {
            writeUTF(playerName)
            writeInt(mPlayerScore)
        }
    }
}

Java

@Override
public void onRestore(BackupDataInput data, int appVersionCode,
                      ParcelFileDescriptor newState) throws IOException {
    // There should be only one entity, but the safest
    // way to consume it is using a while loop
    while (data.readNextHeader()) {
        String key = data.getKey();
        int dataSize = data.getDataSize();

        // If the key is ours (for saving top score). Note this key was used when
        // we wrote the backup entity header
        if (TOPSCORE_BACKUP_KEY.equals(key)) {
            // Create an input stream for the BackupDataInput
            byte[] dataBuf = new byte[dataSize];
            data.readEntityData(dataBuf, 0, dataSize);
            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
            DataInputStream in = new DataInputStream(baStream);

            // Read the player name and score from the backup data
            playerName = in.readUTF();
            playerScore = in.readInt();

            // Record the score on the device (to a file or something)
            recordScore(playerName, playerScore);
        } else {
            // We don't know this entity key. Skip it. (Shouldn't happen.)
            data.skipEntityData();
        }
    }

    // Finally, write to the state blob (newState) that describes the restored data
    FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
    DataOutputStream out = new DataOutputStream(outstream);
    out.writeUTF(playerName);
    out.writeInt(mPlayerScore);
}

In diesem Beispiel ist der an onRestore() übergebene Parameter appVersionCode nicht verwendet. Sie können sie jedoch verwenden, wenn Sie eine Sicherung durchführen, während die Version der App des Nutzers tatsächlich rückwärts gewechselt ist (z. B. von Version 1.5 Ihrer App zu Version 1.0). Weitere Informationen finden Sie im nächsten Abschnitt.

Version der wiederherzustellenden Daten prüfen

Wenn der Sicherungsmanager Ihre Daten im Cloud-Speicher speichert, wird automatisch die Version Ihrer App gemäß dem android:versionCode-Attribut Ihrer Manifestdatei eingeschlossen. Bevor der Sicherungsmanager Ihren Sicherungsagenten zur Wiederherstellung Ihrer Daten aufruft, prüft er die android:versionCode der installierten App und vergleicht sie mit dem im Datensatz für die Wiederherstellung aufgezeichneten Wert. Wenn die im Wiederherstellungsdatensatz aufgezeichnete Version neuer als die App-Version auf dem Gerät ist, hat der Nutzer ein Downgrade seiner App durchgeführt. In diesem Fall beendet der Sicherungsmanager den Wiederherstellungsvorgang für Ihre App und ruft Ihre onRestore()-Methode nicht auf, da der Wiederherstellungssatz für eine ältere Version als bedeutungslos gilt.

Sie können dieses Verhalten mit dem Attribut android:restoreAnyVersion überschreiben. Legen Sie dieses Attribut auf true fest, um anzugeben, dass Sie die App wiederherstellen möchten unabhängig von der Version des Wiederherstellungssatzes. Der Standardwert ist false. Wenn Sie auf true setzen, ignoriert der Sicherungsmanager die android:versionCode und rufen Sie in allen Fällen die Methode onRestore() auf. In der Praxis Sie können den Versionsunterschied in der Datei „onRestore()“ also manuell prüfen. und alle erforderlichen Schritte unternehmen, um die Daten kompatibel zu machen, wenn die Versionen nicht übereinstimmen.

Zur Unterstützung verschiedener Versionen während eines Wiederherstellungsvorgangs Die Methode onRestore() übergibt Ihnen den Versionscode, der in den Wiederherstellungsdaten enthalten ist. als appVersionCode-Parameter festgelegt. Anschließend können Sie den Versionscode der aktuellen App mit dem Feld PackageInfo.versionCode abfragen. Beispiel:

Kotlin

val info: PackageInfo? = try {
    packageManager.getPackageInfo(packageName, 0)
} catch (e: PackageManager.NameNotFoundException) {
    null
}

val version: Int = info?.versionCode ?: 0

Java

PackageInfo info;
try {
    String name = getPackageName();
    info = getPackageManager().getPackageInfo(name, 0);
} catch (NameNotFoundException nnfe) {
    info = null;
}

int version;
if (info != null) {
    version = info.versionCode;
}

Vergleiche dann die version, die von PackageInfo abgerufen wurde, mit der appVersionCode, die an onRestore() übergeben wurde.

Sicherung anfordern

Sie können jederzeit eine Sicherung anfordern, indem Sie dataChanged() aufrufen. Dieses informiert den Sicherungsmanager darüber, dass Sie Ihre Daten mithilfe der Ihren Backup-Agent. Der Sicherungsmanager ruft dann zu einem späteren Zeitpunkt die Methode onBackup() Ihres Sicherungsagenten auf. Normalerweise sollten Sie jedes Mal, wenn sich Ihre Daten ändern, ein Back-up anfordern, z. B. wenn der Nutzer eine App-Einstellung ändert, die Sie sichern möchten. Wenn du dataChanged() mehrmals anrufst, bevor der Sicherungsmanager ein Back-up von deinem Kundenservicemitarbeiter anfordert, erhält dieser nur einen Anruf an onBackup().

Wiederherstellung beantragen

Während der normalen Lebensdauer Ihrer App sollten Sie keine Wiederherstellung anfordern müssen. Das System sucht automatisch nach Sicherungsdaten und führt eine Wiederherstellung durch, wenn Ihre App installiert wird.

Zur automatischen Sicherung migrieren

Du kannst deine App auf vollständige Datensicherungen umstellen, indem du Folgendes konfigurierst: android:fullBackupOnly zu true im <application>-Element in der Manifestdatei. Wenn Ihre App auf einem Gerät mit Android 5.1 (API-Level 22) oder niedriger ausgeführt wird, wird dieser Wert im Manifest ignoriert und es werden weiterhin Schlüssel/Wert-Sicherungen durchgeführt. Wenn Ihre App auf einem Gerät mit Android 6.0 (API-Level 23) oder höher ausgeführt wird, führt sie ein automatisches Back-up anstelle eines Schlüssel/Wert-Back-ups durch.

Datenschutz

Wir bei Google sind uns des Vertrauens bewusst, das Nutzer uns entgegenbringen, und unserer Verantwortung, die Privatsphäre der Nutzer zu schützen. Google überträgt Sicherungsdaten sicher zwischen Google-Servern, um Sicherungs- und Wiederherstellungsfunktionen bereitzustellen. Google behandelt diese Daten gemäß der Datenschutzerklärung von Google als personenbezogene Daten.

Außerdem können Nutzer die Datensicherungsfunktion über die Sicherungseinstellungen des Android-Systems deaktivieren. Wenn ein Nutzer die Sicherung deaktiviert, wird der Android Backup Service werden alle gespeicherten Sicherungsdaten gelöscht. Nutzer können die Sicherung auf dem Gerät wieder aktivieren, aber der Android-Sicherungsdienst stellt keine zuvor gelöschten Daten wieder her.