Android Backup Service fornisce il backup e il ripristino dello spazio di archiviazione sul cloud per i dati chiave-valore nella tua app per Android. Durante un'operazione di backup chiave-valore, i dati di backup dell'app vengono passati al trasporto di backup del dispositivo. Se il dispositivo utilizza il Trasferimento di copie di backup di Google predefinito, i dati vengono trasmessi ad Android Backup Service per l'archiviazione.
I dati sono limitati a 5 MB per utente della tua app. Non è previsto alcun addebito per l'archiviazione dei dati di backup.
Per una panoramica delle opzioni di backup di Android e indicazioni su quali dati eseguire il backup e il ripristino, consulta la Panoramica del backup dei dati.
Implementa il backup di coppie chiave-valore
Per eseguire il backup dei dati dell'app, devi implementare un agente di backup. L'agente di backup viene chiamato dal gestore di backup sia durante il backup sia durante il ripristino.
Per implementare un agente di backup, devi:
Dichiara l'agente di backup nel file manifest con l'attributo
android:backupAgent.Definisci un agente di backup eseguendo una delle seguenti operazioni:
-
La classe
BackupAgentfornisce l'interfaccia centrale utilizzata dalla tua app per comunicare con Backup Manager. Se estendi direttamente questa classe, devi eseguire l'override dionBackup()eonRestore()per gestire le operazioni di backup e ripristino dei dati. Estensione di
BackupAgentHelperLa classe
BackupAgentHelperfornisce un comodo wrapper per la classeBackupAgent, riducendo al minimo la quantità di codice da scrivere. Nel tuoBackupAgentHelper, devi utilizzare uno o più oggetti helper, che eseguono automaticamente il backup e il ripristino di determinati tipi di dati, in modo da non dover implementareonBackup()eonRestore(). A meno che tu non abbia bisogno del controllo completo dei backup della tua app, ti consigliamo di utilizzareBackupAgentHelperper gestire i backup della tua app.Al momento, Android fornisce helper di backup che eseguono il backup e il ripristino di file completi da
SharedPreferencese dalla memoria interna.
-
Dichiara l'agente di backup nel manifest
Dopo aver 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 file manifest Android. Android Backup Service non richiede più una chiave di servizio, ma alcuni dispositivi meno recenti potrebbero comunque verificare la presenza di una chiave durante il backup. Imposta android:name su com.google.android.backup.api_key e
android:value su unused.
L'attributo android:restoreAnyVersion accetta un valore booleano per indicare se vuoi ripristinare i dati dell'app indipendentemente dalla versione corrente dell'app rispetto alla versione che ha prodotto i dati di backup. Il valore predefinito è false. Per saperne di più, consulta Controlla la versione dei dati di ripristino.
Estendi BackupAgentHelper
Se vuoi eseguire il backup di file completi da SharedPreferences o dallo spazio di archiviazione interno, devi creare l'agente di backup utilizzando BackupAgentHelper.
La creazione dell'agente di backup con BackupAgentHelper richiede molto meno codice rispetto
all'estensione di BackupAgent, perché non è necessario implementare onBackup() e
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 particolare tipo di dati. Il framework Android attualmente fornisce due diversi helper:
SharedPreferencesBackupHelperper eseguire il backup diSharedPreferencesfile.FileBackupHelperper eseguire il backup dei file dalla memoria interna.
Puoi includere più helper nel tuo BackupAgentHelper, ma ne è necessario solo uno per ogni tipo di dati. In altre parole, se hai più file SharedPreferences, ti serve un solo file SharedPreferencesBackupHelper.
Per ogni helper che vuoi aggiungere a BackupAgentHelper, devi eseguire le seguenti operazioni durante il metodo onCreate():
- Crea un'istanza della classe helper selezionata. Nel costruttore della classe, devi specificare i file di cui vuoi eseguire il backup.
- Chiama
addHelper()per aggiungere l'assistente al tuoBackupAgentHelper.
Le sezioni seguenti descrivono come creare un agente di backup utilizzando ciascuno degli helper disponibili.
Esegui il backup di SharedPreferences
Quando crei un'istanza di un SharedPreferencesBackupHelper, devi includere il nome di uno o più file SharedPreferences.
Ad esempio, per eseguire il backup di un file SharedPreferences denominato user_preferences, un agente di backup completo che utilizza 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);
}
}
SharedPreferencesBackupHelper include tutto il codice necessario per eseguire il backup e il ripristino di un file SharedPreferences.
Quando il gestore dei backup chiama onBackup() e onRestore(),
BackupAgentHelper chiama i tuoi helper di backup per eseguire il backup e il ripristino dei
file specificati.
Esegui il backup di altri file
Quando crei un'istanza di FileBackupHelper, devi includere il nome di uno o più file salvati nello spazio di archiviazione interno della tua 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 che utilizza 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 eseguire il backup e il ripristino dei file salvati nello spazio di archiviazione interno della tua app.
Tuttavia, la lettura e la scrittura di file nella memoria interna non sono thread-safe. Per assicurarti che l'agente di backup non legga o scriva i tuoi 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, hai bisogno di 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, ecco un'istruzione sincronizzata per scrivere l'ultimo punteggio di un gioco in un file:
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.
Quindi, nel tuo BackupAgentHelper, devi eseguire l'override di onBackup() e onRestore() per sincronizzare le operazioni di backup e ripristino con lo stesso blocco intrinseco. Ad esempio, l'esempio MyFileBackupAgent precedente richiede 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 aver bisogno di estendere direttamente la classe BackupAgent, ma dovrebbe invece estendere BackupAgentHelper per sfruttare le classi helper integrate che eseguono automaticamente il backup e il ripristino dei file.
Tuttavia, puoi estendere direttamente BackupAgent per:
- Crea una versione del formato dei dati. Ad esempio, se prevedi di dover rivedere 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 le operazioni di compatibilità necessarie se la versione sul dispositivo è diversa da quella dei dati di backup. Per saperne di più, consulta Controlla 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 il modo in cui ogni parte viene poi ripristinata sul dispositivo. In questo modo puoi anche gestire diverse versioni, perché leggi e scrivi i dati come entità uniche, anziché come file completi.
- Esegui il backup dei dati in un database. Se hai un database SQLite che vuoi ripristinare quando l'utente reinstalla la tua app, devi creare un
BackupAgentpersonalizzato che legga i dati appropriati durante un'operazione di backup, quindi creare la tabella e inserire i dati durante un'operazione di ripristino.
Se non devi eseguire nessuna delle attività precedenti e vuoi eseguire il backup di file completi da SharedPreferences o dallo spazio di archiviazione interno, consulta Estensione di BackupAgentHelper.
Metodi richiesti
Quando crei un BackupAgent, devi implementare i seguenti metodi di callback:
onBackup()- Il gestore dei backup chiama questo metodo dopo che hai richiesto un backup. In questo metodo, leggi i dati dell'app dal dispositivo e passi i dati di cui vuoi eseguire il backup al Gestore dei backup, come descritto in Esegui un backup.
onRestore()Il gestore dei backup chiama questo metodo durante un'operazione di ripristino. Questo metodo fornisce i dati di backup, che l'app può utilizzare per ripristinare lo stato precedente, come descritto in Esegui un ripristino.
Il sistema chiama questo metodo per ripristinare i dati di backup quando l'utente reinstalla l'app, ma l'app può anche richiedere un ripristino.
Esegui un backup
Una richiesta di backup non comporta una chiamata immediata al metodo onBackup(). Il gestore dei backup attende invece un momento appropriato, quindi esegue un backup per tutte le app che hanno richiesto un backup dall'ultimo backup eseguito. A questo punto devi fornire i dati dell'app al Backup Manager in modo che possano essere salvati nello spazio di archiviazione sul cloud.
Solo Backup Manager può chiamare il metodo onBackup() dell'agente di backup. Ogni volta che i dati dell'app cambiano e vuoi eseguire un backup, devi richiedere un'operazione di backup chiamando dataChanged().
Per saperne di più, consulta Richiedi un backup.
Suggerimento: durante lo sviluppo dell'app, puoi avviare un'operazione di backup immediata dal Gestore backup con lo strumento bmgr.
Quando il gestore dei backup chiama il metodo onBackup(), passa tre
parametri:
oldState- Un
ParcelFileDescriptoraperto in sola lettura che punta all'ultimo stato di backup fornito dalla tua app. Non si tratta dei dati di backup dello spazio di archiviazione sul cloud, ma di una rappresentazione locale dei dati di cui è stato eseguito il backup l'ultima volta che è stato chiamatoonBackup(), come definito danewStateo daonRestore().onRestore()è trattato nella sezione successiva. PoichéonBackup()non ti consente di leggere i dati di backup esistenti nello spazio di archiviazione sul cloud, puoi utilizzare questa rappresentazione locale per determinare se i tuoi dati sono cambiati dall'ultimo backup. data- Un oggetto
BackupDataOutput, che utilizzi per inviare i dati di backup a Backup Manager. newState- Un
ParcelFileDescriptoraperto in lettura e scrittura che punta a un file in cui devi scrivere una rappresentazione dei dati che hai inviato adata. Una rappresentazione può essere il timestamp dell'ultima modifica del file. Questo oggetto viene restituito comeoldStatela volta successiva che Backup Manager chiama il tuo metodoonBackup(). Se non scrivi i dati di backup innewState,oldStatefarà riferimento a un file vuoto la prossima volta che Backup Manager chiameràonBackup().
Utilizzando questi parametri, implementa il metodo onBackup() per eseguire le seguenti operazioni:
Verifica se i dati sono cambiati dall'ultimo backup confrontando
oldStatecon i dati attuali. Il modo in cui leggi i dati inoldStatedipende da come li hai scritti originariamente innewState(vedi il passaggio 3). Il modo più semplice per registrare lo stato di un file è utilizzare il timestamp dell'ultima modifica. Ad esempio, ecco come puoi leggere e confrontare un timestamp dioldState: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 hai bisogno di eseguire il backup, vai al passaggio 3.
Se i tuoi dati sono cambiati rispetto a
oldState, scrivi i dati correnti indataper eseguirne il backup nello spazio di archiviazione sul cloud.Devi scrivere ogni blocco di dati come entità in
BackupDataOutput. Un'entità è un record di dati binari flattizzati identificato da una stringa di chiave univoca. Pertanto, il set di dati di cui esegui il backup è concettualmente un insieme di coppie chiave-valore.Per aggiungere un'entità al set di dati di backup, devi:
Chiama
writeEntityHeader(), passando una chiave di stringa univoca per i dati che stai per scrivere e la dimensione dei dati.Chiama
writeEntityData(), passando un buffer di byte che contiene i tuoi dati e il numero di byte da scrivere dal buffer, che deve corrispondere alla dimensione passata awriteEntityHeader().
Ad esempio, il codice seguente appiattisce alcuni dati in un flusso 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 using 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. La suddivisione dei dati in entità dipende da te. Potresti anche utilizzare una sola entità.
Indipendentemente dal fatto che tu esegua o meno un backup (nel passaggio 2), scrivi una rappresentazione dei dati attuali in
newStateParcelFileDescriptor. Il gestore dei backup conserva questo oggetto localmente come rappresentazione dei dati di cui è attualmente eseguito il backup. Questo valore ti viene restituito comeoldStatela volta successiva che chiamaonBackup(), in modo che tu possa determinare se è necessario un altro backup, come gestito nel passaggio 1. Se non scrivi lo stato dei dati corrente in questo file,oldStatesarà vuoto durante il callback successivo.L'esempio seguente salva una rappresentazione dei dati correnti in
newStateutilizzando 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 dell'app, il gestore dei backup chiama il metodo onRestore() dell'agente di backup. Quando chiama questo metodo, il gestore dei backup
fornisce i dati di backup in modo che tu possa ripristinarli sul dispositivo.
Solo il gestore dei backup può chiamare onRestore(), il che avviene automaticamente quando il sistema installa la tua app e trova dati di backup esistenti.
Quando il gestore dei 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 dell'attributo manifest
android:versionCodedella tua app, così come era al momento del backup dei dati. Puoi utilizzarlo per verificare la versione corrente dell'app e determinare se il formato dei dati è compatibile. Per saperne di più su come utilizzarlo per gestire diverse versioni dei dati di ripristino, consulta Controlla la versione dei dati di ripristino. newState- Un
ParcelFileDescriptoraperto in lettura e scrittura che punta a un file in cui devi scrivere lo stato di backup finale fornito condata. Questo oggetto viene restituito comeoldStatela volta successiva che viene chiamatoonBackup(). Ricorda che devi anche scrivere lo stesso oggettonewStatenel callbackonBackup(). Se lo fai anche qui, l'oggettooldStateassegnato aonBackup()sarà valido anche la prima volta cheonBackup()viene chiamato dopo il ripristino del dispositivo.
Nella tua implementazione di onRestore(), devi chiamare
readNextHeader()
su data per eseguire l'iterazione di tutte le entità nel set di dati. Per ogni entità trovata, segui questi passaggi:
- Recupera la chiave dell'entità con
getKey(). Confronta la chiave entità con un elenco di valori chiave noti che dovresti aver dichiarato come stringhe finali statiche all'interno della classe
BackupAgent. Quando la chiave corrisponde a una delle stringhe di chiavi note, inserisci un'istruzione per estrarre i dati dell'entità e salvarli sul dispositivo:- Ottieni le dimensioni dei dati dell'entità con
getDataSize()e crea un array di byte di queste dimensioni. - Chiama
readEntityData()e passagli l'array di byte, che è dove andranno i dati, e specifica l'offset iniziale e la dimensione da leggere. - L'array di byte è ora pieno. Leggi i dati e scrivili sul dispositivo come preferisci.
- Ottieni le dimensioni dei dati dell'entità con
Dopo aver letto e scritto i dati sul dispositivo, scrivi lo stato dei dati nel parametro
newStatecome fai duranteonBackup().
Ad esempio, ecco come puoi ripristinare i dati di cui è stato eseguito il backup nell'esempio della 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, potresti volerlo utilizzare se hai scelto di eseguire un backup quando la versione dell'app dell'utente è stata effettivamente spostata indietro (ad esempio, l'utente è passato dalla versione 1.5 dell'app alla versione 1.0). Per saperne di più, consulta la sezione successiva.
Controlla la versione dei dati di ripristino
Quando il gestore dei backup salva i dati nello spazio di archiviazione sul cloud, include automaticamente la versione della tua app, come definita dall'attributo android:versionCode del file manifest. Prima che il gestore dei backup chiami l'agente di backup per ripristinare i dati, esamina il android:versionCode dell'app 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 della versione dell'app sul
dispositivo, l'utente ha eseguito il downgrade dell'app. In questo caso, Backup
Manager interromperà l'operazione di ripristino per l'app e non chiamerà il
metodo onRestore(), perché il set di ripristino è considerato privo di significato per una
versione precedente.
Puoi eseguire l'override di questo comportamento utilizzando l'attributo android:restoreAnyVersion:
false(predefinito): Backup Manager interrompe l'operazione di ripristino se la versione registrata nel set di dati di ripristino è più recente della versione dell'app sul dispositivo.true: il gestore dei backup ignoraandroid:versionCodee chiama il tuo metodoonRestore()in tutti i casi, in modo da poter verificare manualmente le differenze di versione e rendere i dati compatibili.
Per aiutarti a gestire le diverse versioni durante un'operazione di ripristino, il metodo onRestore() ti passa il codice di versione incluso nel set di dati di ripristino come parametro appVersionCode. Puoi quindi eseguire una query sul codice di 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 il version acquisito da PackageInfo con il appVersionCode passato a onRestore().
Richiedi un backup
Puoi richiedere un'operazione di backup in qualsiasi momento chiamando dataChanged(). Questo metodo comunica al Backup Manager che vuoi eseguire il backup dei dati utilizzando l'agente di backup. Il gestore dei backup chiama quindi il metodo onBackup() dell'agente di backup in un secondo momento. 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 prima che Backup Manager richieda un backup all'agente, quest'ultimo riceve comunque una sola chiamata a onBackup().
Richiedi un ripristino
Durante il normale ciclo di vita della tua app, non dovresti avere bisogno di richiedere un'operazione di ripristino. Il sistema verifica automaticamente la presenza di dati di backup ed esegue un ripristino quando l'app viene installata.
Esegui la migrazione al backup automatico
Puoi eseguire la transizione della tua app ai backup completi dei dati impostando
android:fullBackupOnly
su true nell'elemento <application> nel file manifest. Se l'app viene eseguita su un dispositivo con Android 5.1 (livello API 22) o versioni precedenti, ignora questo valore nel manifest e continua a eseguire i backup di coppie chiave-valore. Quando viene eseguita su un dispositivo con Android 6.0 (livello API 23) o versioni successive, la tua app esegue il backup automatico anziché il backup di coppie chiave-valore.
Privacy dell'utente
Noi di Google siamo consapevoli della fiducia che gli utenti ripongono in noi e della nostra responsabilità di proteggere la loro privacy. Google trasmette in modo sicuro i dati di backup da e verso i server Google per fornire funzionalità di backup e ripristino. Google tratta questi dati come informazioni personali in conformità alle Norme sulla privacy di Google.
Inoltre, gli utenti possono disattivare la funzionalità di backup dei dati tramite le impostazioni di backup del sistema Android. 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 eliminati in precedenza.