Eseguire il backup delle coppie chiave-valore con Android Backup Service

Android Backup Service fornisce il backup e il ripristino dello spazio di archiviazione sul cloud per le coppie chiave-valore nella tua app per Android. Durante un'operazione di backup di una coppia chiave-valore, il backup vengono trasmessi al trasporto di backup del dispositivo. Se il dispositivo utilizza il metodo di trasporto del backup di Google predefinito, i dati vengono trasmessi al Servizio di backup di Android per l'archiviazione.

I dati sono limitati a 5 MB per utente della tua app. Lo stoccaggio degli dati di backup non comporta costi.

Per una panoramica delle opzioni di backup di Android e indicazioni su quali dati eseguire il backup e il ripristino, consulta la sezione Backup Panoramica.

Implementare il backup delle coppie chiave-valore

Per eseguire il backup dei dati dell'app, devi implementare un agente di backup. L'agente di backup viene chiamato da Backup Manager sia durante il backup sia durante il ripristino.

Per implementare un agente di backup, devi:

  1. Dichiara l'agente di backup nel file manifest con android:backupAgent .

  2. Per definire un agente di backup, svolgi una delle seguenti operazioni:

    • Estensione BackupAgent

      La classe BackupAgent fornisce l'interfaccia centrale utilizzata dalla tua app per comunicare con Backup Manager. Se estendi direttamente questa classe, devi sostituire onBackup() e onRestore() per gestire le operazioni di backup e ripristino per i tuoi dati.

    • Estensione BackupAgentHelper

      La classe BackupAgentHelper fornisce un pratico wrapper per la classe BackupAgent, minimizzando la quantità di codice da scrivere. Nel tuo BackupAgentHelper, devi utilizzare uno o più oggetti helper, che eseguire automaticamente il backup e il ripristino di determinati tipi di dati, in modo che devono implementare onBackup() e onRestore(). A meno che tu non abbia bisogno del controllo completo dei backup della tua app, ti consigliamo di utilizzare BackupAgentHelper per gestirli.

      Android attualmente fornisce assistenti per il backup e il ripristino completa i file da SharedPreferences e archiviazione interna.

Dichiara l'agente di backup nel file manifest

Una volta deciso il nome della classe per l'agente di backup, dichiaralo nel manifest utilizzando l'attributo android:backupAgent nel tag <application>.

Ad esempio:

<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>

Per supportare i dispositivi meno recenti, ti consigliamo di aggiungere la chiave API <meta-data> al tuo file manifest Android. Android Backup Service non richiede più chiave di servizio, ma alcuni dispositivi meno recenti potrebbero comunque verificare la presenza di una chiave durante il backup verso l'alto. Imposta android:name su com.google.android.backup.api_key e android:value su unused.

La android:restoreAnyVersion assume un valore booleano per indicare se vuoi ripristinare l'app di dati a prescindere dalla versione corrente dell'app rispetto alla versione generato i dati di backup. Il valore predefinito è false. Per ulteriori informazioni, consulta Verificare la versione dei dati di ripristino.

Estendi BackupAgentHelper

Se vuoi, devi creare il tuo agente di backup utilizzando BackupAgentHelper esegui il backup di file completi da SharedPreferences o dalla memoria interna. La creazione dell'agente di backup con BackupAgentHelper richiede molto meno codice rispetto estendendo BackupAgent, perché non devi implementare onBackup() onRestore().

La tua implementazione di BackupAgentHelper deve utilizzare uno o più helper di backup. Un helper di backup è un componente specializzato che BackupAgentHelper richiama per eseguire operazioni di backup e ripristino per un determinato tipo di dati. La Il framework Android al momento fornisce due diversi tipi di supporto:

Puoi includere più helper in BackupAgentHelper, ma è necessario un solo helper per ogni tipo di dati. Vale a dire che se disponi di più SharedPreferences file, ti serve solo uno SharedPreferencesBackupHelper.

Per ogni aiutante che vuoi aggiungere al tuo BackupAgentHelper, devi eseguire le seguire durante Metodo onCreate():

  1. Crea un'istanza della classe di helper desiderata. Nel constructor della classe, devi specificare i file di cui vuoi eseguire il backup.
  2. Chiama addHelper() per aggiungere l'assistente al tuo BackupAgentHelper.

Le sezioni seguenti descrivono come creare un agente di backup utilizzando ciascuno degli aiutanti disponibili.

Esegui il backup di SharedPreferences

Quando crei un'istanza di SharedPreferencesBackupHelper, devi includere il nome di uno o più file SharedPreferences.

Ad esempio, per eseguire il backup di un file SharedPreferences denominato user_preferences, viene eseguita l'agente di backup completo utilizzando BackupAgentHelper ha il seguente aspetto:

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

Il file SharedPreferencesBackupHelper include tutto il codice necessario per eseguire il backup e il recupero di un file SharedPreferences.

Quando Gestione backup chiama onBackup() e onRestore(), BackupAgentHelper chiama gli assistenti di backup per eseguire il backup e ripristinare il tuo nei file specificati.

Esegui il backup di altri file

Quando esegui l'inizializzazione di un FileBackupHelper, devi includere il nome di uno o più file salvati nello spazio di archiviazione interno dell'app, come specificato da getFilesDir(), che è la stessa posizione in cui openFileOutput() scrive i file.

Ad esempio, per eseguire il backup di due file denominati scores e stats, un agente di backup utilizzando BackupAgentHelper ha il seguente aspetto:

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 include tutto il codice necessario per il backup e il ripristino salvati nella memoria interna dell'app.

Tuttavia, la lettura e la scrittura su file nella memoria interna non sono thread-safe. Per assicurarti che l'agente di backup non legga o scriva i file contemporaneamente alle tue attività, devi utilizzare istruzioni sincronizzate ogni volta che esegui una lettura o una scrittura. Ad esempio, in qualsiasi attività in cui leggi e scrivi il file, devi avere un oggetto da utilizzare come blocco intrinseco per le istruzioni sincronizzate:

Kotlin

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

Java

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

Quindi, crea un'istruzione sincronizzata con questo blocco ogni volta che leggi o scrivi i file. Ad esempio, di seguito è riportato un'istruzione sincronizzata per scrivere in un file il punteggio più recente di una partita:

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

Devi sincronizzare le istruzioni di lettura con lo stesso blocco.

Poi, in BackupAgentHelper, devi sostituire onBackup() e onRestore() per sincronizzare le operazioni di backup e ripristino con lo stesso blocco intrinseco. Ad esempio, l'esempio MyFileBackupAgent delle esigenze precedenti utilizza i seguenti metodi:

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

Estendi BackupAgent

La maggior parte delle app non dovrebbe dover estendere direttamente la classe BackupAgent, ma dovrebbe invece estendere BackupAgentHelper per sfruttare le classi di assistenza integrate che eseguono automaticamente il backup e il ripristino dei file. Tuttavia, puoi estendere BackupAgent direttamente per:

  • Esegui la versione del formato dei dati. Ad esempio, se prevedi di dover revisionare il formato in cui scrivi i dati dell'app, puoi creare un agente di backup per verificare la versione dell'app durante un'operazione di ripristino ed eseguire eventuali operazioni di compatibilità necessarie se la versione sul dispositivo è diversa da quella dei dati di backup. Per ulteriori informazioni, vedi Verificare la versione dei dati di ripristino.
  • Specifica le parti di dati di cui eseguire il backup. Anziché eseguire il backup di un intero file, puoi specificare le parti di dati di cui eseguire il backup e la modalità di ripristino di ciascuna parte sul dispositivo. Questo può anche aiutarti a gestire versioni diverse, perché leggi e scrivi i dati come entità univoche anziché come file completi.
  • Esegui il backup dei dati in un database. Se vuoi usare un database SQLite da ripristinare quando l'utente reinstalla la tua app, devi creare un BackupAgent che legge i dati appropriati durante un'operazione di backup, poi crea la tabella e inserisci i dati durante un'operazione di ripristino.

Se non devi eseguire nessuna delle attività indicate sopra e vuoi eseguire il backup completa i file da SharedPreferences o dalla memoria interna, consulta Estensione BackupAgentHelper.

Metodi obbligatori

Quando crei un BackupAgent, devi implementare i seguenti metodi callback:

onBackup()
Il Gestore backup chiama questo metodo dopo che hai richiesto un di backup. Con questo metodo, leggi i dati dell'app dal dispositivo e passa i dati di cui vuoi eseguire il backup a Gestione backup, come descritto in Eseguire un backup.
onRestore()

Il Gestore backup chiama questo metodo durante un'operazione di ripristino. Questo metodo fornisce i tuoi dati di backup, che l'app può utilizzare per ripristinare i dati precedenti come descritto in Eseguire un ripristino.

Il sistema chiama questo metodo per ripristinare i dati di backup quando l'utente reinstalla l'app, ma quest'ultima può anche richiedere una ripristina.

Esegui un backup

Una richiesta di backup non comporta una chiamata immediata al metodo onBackup(). Backup Manager attende invece il momento opportuno, quindi esegue un backup di tutte le app che ne hanno richiesto uno dall'ultimo backup. A questo punto devi fornire i dati dell'app in Gestione backup per poterlo salvare nello spazio di archiviazione sul cloud.

Solo Backup Manager può chiamare il metodo onBackup() dell'agente di backup. Ciascuna volta che i dati dell'app vengono modificati ed eseguire il backup, devi per richiedere un'operazione di backup chiamando dataChanged() Per saperne di più, vedi Richiedere un backup.

Suggerimento: durante lo sviluppo dell'app, puoi avviare un backup immediato dell'operazione da Gestione backup con bmgr strumento.

Quando Backup Manager chiama il metodo onBackup(), passa tre parametri:

oldState
Un indirizzo aperto di sola lettura ParcelFileDescriptor con destinazione all'ultimo stato di backup fornito dall'app. Questi non sono i dati di backup da spazio di archiviazione sul cloud, ma una rappresentazione locale dei dati di cui è stato eseguito il backup L'ultima volta che è stata chiamata onBackup(), come definito da newState o da onRestore(). onRestore() verrà trattato nella sezione successiva. Poiché onBackup() non consente di leggere i dati di backup esistenti nel cloud di archiviazione, puoi utilizzare questa rappresentazione locale per determinare se i tuoi dati è cambiato rispetto all'ultimo backup.
data
Un BackupDataOutput utilizzato per caricare i dati di backup in Gestione backup.
newState
Un ParcelFileDescriptor aperto in lettura/scrittura che rimanda a un file in cui devi scrivere una rappresentazione dei dati che hai inviato a data. R una rappresentazione può essere semplice come il timestamp dell'ultima modifica del file. Questo oggetto viene restituito come oldState alla successiva chiamata del metodo onBackup() da parte di Backup Manager. Se non scrivi i dati di backup su newState, allora oldState punterà a un file vuoto la prossima volta che chiamerà Gestione backup onBackup().

Utilizzando questi parametri, implementa il metodo onBackup() per:

  1. Controlla se i dati sono cambiati dall'ultimo backup confrontandoli con quelli attuali.oldState La modalità di lettura dei dati in oldState dipende da come l'hai scritto originariamente in newState (vedi il passaggio 3). Il modo più semplice registra lo stato di un file con il timestamp dell'ultima modifica. Ad esempio: Per leggere e confrontare un timestamp di oldState, procedi nel seguente modo:

    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
    }

    Se non è cambiato nulla e non devi eseguire il backup, vai al passaggio 3.

  2. Se i dati sono cambiati rispetto a oldState, scrivi i dati attuali in data per eseguirne il backup nello spazio di archiviazione sul cloud.

    Devi scrivere ogni blocco di dati come entità in BackupDataOutput. Un L'entità è un record di dati binario appiattito identificato da una chiave univoca stringa. Pertanto, il set di dati di cui esegui il backup è concettualmente un insieme coppie chiave-valore.

    Per aggiungere un'entità al set di dati di backup, devi:

    1. Chiama writeEntityHeader(), passando una chiave di stringa univoca per i dati che stai per scrivere e le dimensioni dei dati.

    2. Chiama writeEntityData(), passare un buffer di byte che contiene i tuoi dati e il numero di byte scrivere dal buffer, che deve corrispondere alla dimensione passata writeEntityHeader().

    Ad esempio, il seguente codice appiattisce alcuni dati in uno stream di byte e li scrive in una singola entità:

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

    Esegui questa operazione per ogni dato di cui vuoi eseguire il backup. Come dividi trasforma i tuoi dati in entità. Puoi anche utilizzare una sola entità.

  3. Indipendentemente dal fatto che tu abbia eseguito o meno un backup (nel passaggio 2), scrivi una rappresentazione i dati attuali al newState ParcelFileDescriptor. Backup Manager conserva questo oggetto localmente come rappresentazione dei dati di cui viene eseguito il backup. Te lo ritrasmette come oldState la prossima volta chiama onBackup() per consentirti di determinare se un altro backup viene necessario, come gestito nel passaggio 1. Se non scrivi lo stato corrente dei dati in questo file, oldState sarà vuoto durante il successivo callback.

    L'esempio seguente salva una rappresentazione dei dati correnti in newState utilizzando il timestamp dell'ultima modifica del file:

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

Esegui un ripristino

Quando è il momento di ripristinare i dati delle app, Backup Manager chiama il metodo onRestore() dell'agente di backup. Quando chiama questo metodo, Gestione backup invia i dati di backup per ripristinarli sul dispositivo.

Solo il gestore backup può chiamare onRestore(). Questa operazione viene eseguita automaticamente Quando il sistema installa l'app e trova i dati di backup esistenti.

Quando Gestione backup chiama il metodo onRestore(), passa tre parametri:

data
Un oggetto BackupDataInput, che ti consente di leggere i dati di backup.
appVersionCode
Un numero intero che rappresenta il valore del parametro android:versionCode , come avveniva al momento del backup di questi dati. Puoi utilizzare questo per eseguire un controllo incrociato della versione corrente dell'app e determinare se il formato dei dati è compatibili. Per ulteriori informazioni sull'utilizzo di questa opzione per gestire diverse versioni dei dati di ripristino, consulta Verificare la versione dei dati di ripristino.
newState
Un file ParcelFileDescriptor aperto in lettura/scrittura che punta a un file in cui deve scrivere lo stato del backup finale fornito con data. Questo oggetto viene restituito come oldState alla successiva chiamata di onBackup(). Ricorda devi anche scrivere lo stesso oggetto newState in onBackup() il callback; in questo caso si garantisce che l'oggetto oldState sia stato assegnato onBackup() è valido anche la prima volta che onBackup() viene chiamato dopo il viene ripristinato sul tuo dispositivo.

Nell'implementazione di onRestore(), devi chiamare readNextHeader() su data per eseguire l'iterazione di tutte le entità nel set di dati. Per ogni entità ritrovata:

  1. Recupera la chiave dell'entità con getKey()
  2. Confronta la chiave dell'entità con un elenco di valori di chiavi noti che dovresti aver dichiarato come stringhe finali statiche all'interno della classe BackupAgent. Quando corrisponde a una delle stringhe di chiavi note, inserisci un'istruzione per estrarre i dati dell'entità e salvarli sul dispositivo:

    1. Ottieni le dimensioni dei dati dell'entità con getDataSize() e crea un array di byte di queste dimensioni.
    2. Chiama readEntityData() e passa l'array di byte, dove verranno memorizzati i dati, e specifica lo spostamento iniziale e le dimensioni da leggere.
    3. L'array di byte è ora completo. Leggi i dati e scrivili sul dispositivo come preferisci.
  3. Dopo aver letto e scritto di nuovo i dati sul dispositivo, scrivi lo stato dei dati nel parametro newState come faresti durante onBackup().

Ad esempio, ecco come ripristinare i dati di cui è stato eseguito il backup nell'esempio sezione precedente:

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 questo esempio, il parametro appVersionCode passato a onRestore() non viene utilizzato. Tuttavia, ti consigliamo di utilizzarlo se hai scelto di eseguire un backup quando la versione dell'app dell'utente è effettivamente passata a una precedente (ad esempio, l'utente è passato dalla versione 1.5 della tua app alla 1.0). Per ulteriori informazioni, vedi nella prossima sezione.

Controlla la versione dei dati di ripristino

Quando Gestione backup salva i dati nello spazio di archiviazione sul cloud, include la versione dell'app, come definita dall'interfaccia utente Attributo android:versionCode. Prima che Gestione backup chiami il tuo backup di ripristino dei dati, viene esaminato il android:versionCode installata e lo confronta con il valore registrato nel set di dati di ripristino. Se la versione registrata nel set di dati di ripristino è più recente rispetto alla versione dell'app sul sul dispositivo, l'utente ha eseguito il downgrade dell'app. In questo caso, il token di backup Il gestore interromperà l'operazione di ripristino per la tua app e non chiamerà il tuo onRestore(), perché il set di ripristino è considerato privo di significato per un precedente.

Puoi ignorare questo comportamento con l'attributo android:restoreAnyVersion. Imposta questo attributo su true per indicare che vuoi ripristinare l'app a prescindere dalla versione del set di ripristino. Il valore predefinito è false. Se lo imposti su true, Backup Manager ignorerà true e chiamerà il metodo onRestore() in tutti i casi. In questo modo, puoi controllare manualmente la differenza di versione nel metodo onRestore() e adottare le misure necessarie per rendere i dati compatibili se le versioni non corrispondono.

Per aiutarti a gestire versioni diverse durante un'operazione di ripristino, Il metodo onRestore() ti trasmette il codice di versione incluso nei dati di ripristino impostato come parametro appVersionCode. Puoi quindi eseguire una query sul codice della versione dell'app corrente con il campo PackageInfo.versionCode. Ad esempio:

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

Poi confronta i valori di version acquisiti da PackageInfo al appVersionCode è passato a onRestore().

Richiedere un backup

Puoi richiedere un'operazione di backup in qualsiasi momento chiamando dataChanged(). Questo metodo informa Backup Manager che vuoi eseguire il backup dei dati utilizzando il tuo agente di backup. Backup Manager chiama quindi il metodo onBackup() dell'agente di backup in un momento successivo. In genere, devi richiedere un backup ogni volta che i dati cambiano (ad esempio quando l'utente modifica una preferenza dell'app di cui vuoi eseguire il backup). Se chiami dataChanged() più volte volte prima che Gestore backup richieda un backup all'agente, quest'ultimo riceve comunque una sola chiamata al numero onBackup().

Richiedere un ripristino

Durante il normale ciclo di vita dell'app, non dovrebbe essere necessario richiedere un ripristino operativa. Il sistema controlla automaticamente i dati di backup ed esegue una ripristinare l'app una volta installata l'app.

Esegui la migrazione al backup automatico

Puoi eseguire la transizione dell'app ai backup completi dei dati impostando android:fullBackupOnly a true nell'elemento <application> del file manifest. Durante l'esecuzione su un dispositivo con Android 5.1 (livello API 22) o versioni precedenti, la tua app ignora questo nel file manifest e continui a eseguire backup delle coppie chiave-valore. Quando viene eseguita su un dispositivo con Android 6.0 (livello API 23) o versioni successive, l'app esegue il backup automatico anziché il backup delle chiavi.

Privacy degli utenti

Google è consapevole della fiducia che gli utenti ripongono in noi e della nostra responsabilità di proteggere la loro privacy. Google trasmette in sicurezza i dati di backup da e verso i server di Google al fine di fornire funzionalità di backup e ripristino. Google tratta questi dati come informazioni personali, in conformità alle Norme sulla privacy.

Inoltre, gli utenti possono disattivare la funzionalità di backup dei dati tramite Android impostazioni di backup del sistema. Quando un utente disattiva il backup, Android Backup Service elimina tutti i dati di backup salvati. Un utente può riattivare il backup sul dispositivo, ma Android Backup Service non ripristinerà i dati precedentemente eliminati.