O Android Backup Service oferece backup e restauração com armazenamento em nuvem para dados de chave-valor no seu app Android. Durante esse tipo de operação, os dados de backup do app são transmitidos para a transferência de backup do dispositivo. Se o dispositivo estiver usando a Transferência de backup padrão do Google, os dados serão transferidos para o Android Backup Service para arquivamento.
Os dados são limitados a 5 MB por usuário do app. Não há cobrança pelo armazenamento dos dados de backup.
Para ver uma visão geral das opções de backup do Android e uma orientação sobre quais dados você precisa armazenar em backup e restaurar, consulte a Visão geral do backup de dados.
Implementar backup de chave-valor
Para fazer backup dos dados do app, é necessário implementar um agente de backup. Seu agente de backup é chamado pelo Backup Manager durante o backup e a restauração.
Para implementar um agente de backup, é necessário:
Declarar o agente de backup no arquivo do manifesto usando o atributo
android:backupAgent
.Definir um agente de backup realizando uma ou mais das ações a seguir:
-
A classe
BackupAgent
fornece a interface central usada pelo app para se comunicar com o Backup Manager. Se você estender essa classe diretamente, será necessário substituir os métodosonBackup()
eonRestore()
para processar as operações de backup e restauração dos dados. -
A classe
BackupAgentHelper
fornece um wrapper conveniente para a classeBackupAgent
, o que diminui a quantidade de código necessária. NoBackupAgentHelper
, é necessário usar um ou mais objetos auxiliares, que fazem o backup e a restauração de determinados tipos de dados automaticamente. Assim, você não precisará implementaronBackup()
eonRestore()
A menos que você precise ter controle total dos backups do app, recomendamos o uso doBackupAgentHelper
para processá-los.Atualmente, o Android oferece auxiliares de backup que farão backup e restauração de arquivos completos das
SharedPreferences
e do armazenamento interno.
-
Declarar o agente de backup no manifesto
Depois de decidir o nome da classe do agente de backup, declare-o
no manifesto usando o atributo android:backupAgent
na tag
<application>
.
Exemplo:
<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>
Para oferecer compatibilidade com dispositivos mais antigos, recomendamos adicionar a chave de API <meta-data>
ao arquivo de manifesto do Android. O Android Backup Service não exige mais uma
chave de serviço, mas alguns dispositivos mais antigos ainda podem verificar a existência de uma chave ao fazer
backup. Defina android:name
como com.google.android.backup.api_key
e
android:value
como unused
.
O
atributo android:restoreAnyVersion
usa um valor booleano para indicar se você quer restaurar os dados
do app, independentemente da versão atual dele em comparação com a versão que
produziu os dados de backup. O valor padrão é false
. Consulte o guia Verificar a versão
dos dados de restauração para mais informações.
Estender o BackupAgentHelper
Crie seu agente de backup usando o BackupAgentHelper
se quiser
fazer backup de arquivos completos das SharedPreferences
ou do armazenamento interno.
A criação do agente de backup usando o BackupAgentHelper
exige muito menos
código do que a extensão do BackupAgent
, porque não é necessário implementar os métodos onBackup()
e
onRestore()
.
Sua implementação do BackupAgentHelper
precisa usar um ou mais auxiliares de backup.
Um auxiliar de backup é um componente especializado que o BackupAgentHelper
invoca para
realizar operações de backup e restauração para um determinado tipo de dado. Atualmente,
o framework do Android oferece dois auxiliares diferentes:
SharedPreferencesBackupHelper
para fazer backup de arquivosSharedPreferences
.FileBackupHelper
para fazer backup de arquivos do armazenamento interno.
É possível incluir vários auxiliares no BackupAgentHelper
, mas apenas um
auxiliar é necessário para cada tipo de dado. Ou seja, se você tem vários
arquivos SharedPreferences
, apenas um
SharedPreferencesBackupHelper
é necessário.
Para cada auxiliar que você quiser adicionar ao BackupAgentHelper
, é preciso fazer
o seguinte durante o método
onCreate()
:
- Criar uma instância da classe auxiliar que você quer usar. No construtor da classe, é preciso especificar quais arquivos que você quer fazer backup.
- Chamar o método
addHelper()
, para adicionar o auxiliar aoBackupAgentHelper
.
As seções a seguir descrevem como criar um agente de backup usando cada auxiliar disponível.
Fazer backup de SharedPreferences
Ao instanciar um SharedPreferencesBackupHelper
, é necessário incluir o
nome de um ou mais arquivos SharedPreferences
.
Por exemplo, para fazer backup de um arquivo SharedPreferences
com o nome user_preferences
, um
agente de backup completo que usa o BackupAgentHelper
ficará assim:
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); } }
O SharedPreferencesBackupHelper
inclui todo o código necessário para fazer o backup e a
restauração de um arquivo de SharedPreferences
.
Quando o Backup Manager chama os métodos onBackup()
e onRestore()
,
o BackupAgentHelper
chama os auxiliares de backup para fazer o backup e a restauração dos
arquivos especificados.
Fazer backup de outros arquivos
Ao instanciar um FileBackupHelper
, é necessário incluir o nome de um ou
mais arquivos salvos no armazenamento interno do app, conforme especificado no método
getFilesDir()
,
que é o mesmo local em que o método
openFileOutput()
grava arquivos.
Por exemplo, para fazer backup de dois arquivos com os nomes scores
e stats
, um agente de backup
usando o BackupAgentHelper
ficará assim:
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); } }
O FileBackupHelper
inclui todo o código necessário para fazer o backup e a restauração
de arquivos salvos no armazenamento interno do app.
No entanto, a leitura e a gravação de arquivos no armazenamento interno não são seguras para linhas de execução. Para garantir que o agente de backup não leia ou grave arquivos ao mesmo tempo que as atividades, é necessário usar instruções sincronizadas todas as vezes que você fizer uma leitura ou gravação. Por exemplo, em qualquer atividade em que você lê e grava o arquivo, é preciso usar um objeto como o bloqueio intrínseco das instruções sincronizadas:
Kotlin
// Object for intrinsic lock companion object { val sDataLock = Any() }
Java
// Object for intrinsic lock static final Object sDataLock = new Object();
Depois, crie uma instrução sincronizada usando esse bloqueio sempre que ler ou gravar os arquivos. Por exemplo, veja uma instrução sincronizada para gravar a pontuação mais recente de um jogo em um arquivo:
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"); }
Sincronize suas instruções de leitura com o mesmo bloqueio.
Em seguida, no BackupAgentHelper
, é preciso substituir os métodos onBackup()
e
onRestore()
para sincronizar as operações de backup e restauração usando o mesmo
bloqueio intrínseco. Por exemplo, o caso com o MyFileBackupAgent
acima precisa
destes métodos:
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); } }
Estender o BackupAgent
A maior parte dos apps não precisa estender a classe BackupAgent
diretamente, mas é necessário
estender o BackupAgentHelper
para aproveitar
as classes auxiliares integradas que fazem o backup e a restauração dos arquivos automaticamente.
No entanto, você pode estender BackupAgent
diretamente para:
- Controlar as versões do seu formato de dados. Por exemplo, se você previr a necessidade de revisar o formato em que os dados do app são gravados, você pode criar um agente de backup para fazer uma verificação cruzada da versão do app durante uma operação de restauração. Faça todo o trabalho de compatibilidade necessário caso a versão no dispositivo seja diferente da versão dos dados de backup. Para ver mais informações, consulte Verificar a versão dos dados de restauração.
- Especificar as partes dos dados para backup. Em vez de fazer backup de um arquivo inteiro, é possível especificar as partes dos dados que serão armazenadas em backup e como cada parte será restaurada no dispositivo. Isso também pode ajudar a gerenciar versões diferentes, porque os dados são lidos e gravados como entidades únicas, em vez de arquivos completos.
- Fazer backup de dados em um banco de dados. Se você quiser restaurar um banco de dados SQLite
quando o usuário reinstalar o app, será necessário criar um
BackupAgent
personalizado que leia os dados corretos durante uma operação de backup. Em seguida, crie uma tabela e insira os dados durante a operação de restauração.
Se você não precisa realizar nenhuma das tarefas acima e quer fazer backup
dos arquivos completos de SharedPreferences
ou do armazenamento interno, consulte Como estender
o BackupAgentHelper
.
Métodos obrigatórios
Ao criar um BackupAgent
, é necessário implementar os seguintes métodos
de callback:
onBackup()
- O Backup Manager chama esse método depois que você solicita um backup. Nesse método, os dados do app são lidos do dispositivo, e os dados que você quer armazenar em backup são transmitidos para o Backup Manager, conforme descrito em Fazer um backup.
onRestore()
O Backup Manager chama esse método durante uma operação de restauração. Esse método exibe os dados de backup, que podem ser usados pelo app para restaurar o estado anterior, conforme descrito em Fazer uma restauração.
O sistema chama esse método para restaurar os dados de backup quando o usuário reinstalar o app, mas o app também poderá solicitar uma restauração.
Fazer um backup
Uma solicitação de backup não resulta em uma chamada imediata para o
método onBackup()
. Em vez disso, o Backup Manager aguarda o momento adequado e faz
o backup de todos os apps que fizeram essa solicitação desde a data
do último backup. Nesse momento, você precisará informar os dados do app
ao Backup Manager para salvá-los no armazenamento em nuvem.
Só o Backup Manager pode chamar o método onBackup()
do agente de backup. Sempre
que os dados do app mudam e você quer fazer um backup, é necessário
solicitar uma operação de backup chamando
dataChanged()
.
Consulte Solicitar um backup para mais informações.
Dica: durante o desenvolvimento do app, é possível iniciar uma operação de backup
imediata usando o Backup Manager com a ferramenta
bmgr
.
Quando o Backup Manager chama o método onBackup()
, ele transmite três
parâmetros:
oldState
- Um
ParcelFileDescriptor
aberto somente leitura, que aponta para o último estado de backup fornecido pelo app. Esses não são os dados de backup do armazenamento em nuvem, mas uma representação local dos dados que foram armazenados na última vez em que o métodoonBackup()
foi chamado, conforme definido pornewState
ou usandoonRestore()
O métodoonRestore()
será abordado na próxima seção. Como o métodoonBackup()
não autoriza a leitura de dados de backup existentes no armazenamento em nuvem, é possível usar essa representação local para determinar se os dados mudaram desde o último backup. data
- Um objeto
BackupDataOutput
, usado para enviar os dados de backup para o Backup Manager. newState
- Um
ParcelFileDescriptor
aberto de leitura/gravação, que aponta para um arquivo em que você precisa gravar uma representação dos dados enviados aodata
. Uma representação pode ser apenas o carimbo de data/hora da última modificação do arquivo. Esse objeto será retornado como ooldState
na próxima vez que o Backup Manager chamar o métodoonBackup()
. Se você não gravar os dados de backup nonewState
, ooldState
apontará um arquivo vazio na próxima vez que o Backup Manager chamar o métodoonBackup()
.
Ao usar esses parâmetros, implemente o método onBackup()
para fazer o seguinte:
Conferir se os dados mudaram desde o último backup, comparando o
oldState
com os dados atuais. A forma como os dados são lidos nooldState
depende de como eles foram gravados originalmente nonewState
. Consulte a etapa 3. A forma mais fácil de registrar o estado de um arquivo é com o carimbo de data/hora da última modificação. Por exemplo, veja como ler e comparar um carimbo de data/hora dooldState
: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 não houve nenhuma mudança e você não precisa de backup, pule para a etapa 3.
Caso seus dados mudem em comparação ao
oldState
, grave os dados atuais emdata
para fazer backup no armazenamento em nuvem.É preciso gravar cada bloco de dados como uma entidade na
BackupDataOutput
. Uma entidade é um registro de dados binários nivelado, identificado por uma string de chave única. Assim, o conjunto de dados armazenado em backup é, conceitualmente, um conjunto de pares de chave-valor.Para adicionar uma entidade ao seu conjunto de dados de backup, é necessário:
chamar o método
writeEntityHeader()
, transmitindo uma chave de string única para os dados que você está prestes a gravar e para o tamanho dos dados;chamar o método
writeEntityData()
, transmitindo um buffer de bytes contendo os dados e o número de bytes a serem gravados do buffer, que precisa corresponder ao tamanho transmitido para o métodowriteEntityHeader()
.
Por exemplo, o código a seguir nivela alguns dados em um fluxo de bytes e o grava em uma única entidade:
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);
Faça isso para cada bloco de dados que você quer armazenar em backup. A forma como você divide os dados em entidades fica a seu critério. Você pode até usar apenas uma entidade.
Independentemente de ter feito um backup ou não na etapa 2, grave uma representação dos dados atuais no
ParcelFileDescriptor
donewState
. O Backup Manager armazena esse objeto localmente como uma representação dos dados que estão em backup no momento. Ele o transmitirá de volta para você comooldState
na próxima vez que chamar o métodoonBackup()
, para que você possa determinar se outro backup é necessário, como mostrado na etapa 1. Se você não gravar o estado atual dos dados nesse arquivo, ooldState
estará vazio durante o próximo callback.O exemplo a seguir salva uma representação dos dados atuais no
newState
, usando o carimbo de data/hora da última modificação do arquivo: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);
Fazer uma restauração
No momento de restaurar os dados do app, o Backup Manager chama o
método onRestore()
do agente de backup. Ao chamar esse método, o Backup Manager
exibe os dados de backup para que você possa restaurá-los no dispositivo.
Apenas o Backup Manager pode chamar onRestore()
, o que acontece automaticamente
quando o sistema instala o app e encontra dados de backup existentes.
Quando o Backup Manager chama o método onRestore()
, ele transmite três
parâmetros:
data
- Um objeto
BackupDataInput
, que permite ler os dados de backup. appVersionCode
- Um número inteiro representando o valor do atributo do manifesto
android:versionCode
do app, como era no momento em que esses dados foram armazenados em backup. Essa opção possibilita verificar a versão atual do app e determinar se o formato de dados é compatível. Para ver mais informações sobre como usar esse recurso para processar diferentes versões de dados de restauração, consulte Verificar a versão dos dados de restauração. newState
- Um
ParcelFileDescriptor
aberto de leitura/gravação, que aponta para um arquivo em que você precisa gravar o estado de backup final fornecido comdata
. Esse objeto será retornado como ooldState
na próxima vez que oonBackup()
for chamado. Lembre-se de que você precisa gravar o mesmo objetonewState
no callbackonBackup()
. Fazer isso neste callback também garante que o objetooldState
enviado ao métodoonBackup()
seja válido mesmo na primeira vez queonBackup()
for chamado depois da restauração do dispositivo.
Na implementação de onRestore()
, é preciso chamar
readNextHeader()
nos data
para iterar todas as entidades no conjunto de dados. Para cada entidade
encontrada, faça o seguinte:
- Para acessar a chave da entidade, use
getKey()
. Compare a chave da entidade com uma lista de chaves-valor conhecidas, que precisam ter sido declaradas como strings estáticas finais dentro da classe
BackupAgent
. Quando a chave corresponder a uma das strings de chave conhecidas, insira uma instrução para extrair os dados da entidade e salve-os no dispositivo:- Veja o tamanho dos dados da entidade usando
getDataSize()
e crie uma matriz de bytes desse tamanho. - Chame
readEntityData()
e transmita a ele a matriz de bytes, que é para onde os dados irão, e especifique o deslocamento inicial e o tamanho a ser lido. - Agora, sua matriz de bytes estará cheia. Leia os dados e grave-os no dispositivo como você quiser.
- Veja o tamanho dos dados da entidade usando
Depois de ler e gravar os dados no dispositivo, grave o estado deles no parâmetro
newState
da mesma forma que faria durante o métodoonBackup()
.
Por exemplo, veja como restaurar os dados armazenados em backup de acordo com o exemplo da seção anterior:
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); }
Nesse exemplo, o parâmetro appVersionCode
transmitido para o método onRestore()
não é
usado. No entanto, você pode querer usá-lo se escolher fazer um backup
quando a versão do app usada pelo usuário regredir, por exemplo,
ele mudar da versão 1.5 do app para a 1.0. Para saber mais, consulte
a próxima seção.
Verificar a versão dos dados de restauração
Quando o Backup Manager salva os dados no armazenamento em nuvem, ele inclui automaticamente
a versão do app, conforme definido pelo atributo android:versionCode
do arquivo
de manifesto. Antes do Backup Manager chamar o agente de backup
para restaurar os dados, ele analisa o android:versionCode
do
app instalado e o compara com o valor registrado no conjunto de dados de restauração. Se
a versão registrada no conjunto de dados de restauração for mais recente do que a versão do app no
dispositivo, o usuário terá feito downgrade do app. Nesse caso, o Backup
Manager cancelará a operação de restauração do app e não chamará o método
onRestore()
, porque o conjunto de restauração será considerado irrelevante para uma
versão mais antiga.
É possível substituir esse comportamento pelo atributo android:restoreAnyVersion
.
Defina esse atributo como true
para indicar que você quer restaurar o app,
independentemente da versão do conjunto de restauração. O valor padrão é false
. Se você
defini-lo como true
, o Backup Manager ignorará o
android:versionCode
e chamará o método onRestore()
em todos os casos. Ao fazer isso,
você poderá conferir manualmente a diferença de versão no método onRestore()
e seguir qualquer etapa necessária para tornar os dados compatíveis se as versões
não corresponderem.
Para lidar com versões diferentes durante uma operação de restauração, o método
onRestore()
transmite o código de versão incluído no conjunto
de dados de restauração como o parâmetro appVersionCode
. Em seguida, é possível consultar o código da versão atual
do app usando o
campo
PackageInfo.versionCode
. Exemplo:
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; }
Então, basta comparar a version
recebida das
PackageInfo
usando o
appVersionCode
transmitido para o método onRestore()
.
Solicitar um backup
Você pode solicitar uma operação de backup a qualquer momento chamando o método dataChanged()
. Esse
método notifica o Backup Manager que você quer fazer backup dos dados usando o
agente de backup. Em seguida, o Backup Manager chamará o método
onBackup()
do agente de backup no futuro. Normalmente, é necessário solicitar um
backup sempre que os dados mudam, por exemplo, quando o usuário muda uma preferência de um app
que você quer armazenar em backup. Se você chamar o método dataChanged()
várias
vezes seguidas antes do Backup Manager solicitar um backup, seu agente
ainda receberá apenas uma chamada para onBackup()
.
Solicitar uma restauração
Durante a vida normal do app, não é necessário solicitar uma operação de restauração. O sistema verifica automaticamente os dados de backup e executa uma restauração quando o app é instalado.
Migrar para o Backup automático
Você pode fazer a transição do app para backups de dados completos configurando
android:fullBackupOnly
como true
no elemento <application>
do arquivo de manifesto. Quando executado
em um dispositivo com o Android 5.1 (nível 22 da API) ou versões anteriores, o app ignorará esse
valor no manifesto e continuará fazendo backups de chave-valor. Quando executado
em um dispositivo com o Android 6.0 (nível 23 da API) ou versões mais recente, o app fará o backup
automático em vez do backup de chave-valor.
Privacidade do usuário
No Google, estamos cientes da confiança que os usuários depositam em nós e da nossa responsabilidade de proteger a privacidade deles. O Google transmite os dados de backup para os próprios servidores e fora deles com segurança para oferecer recursos de backup e restauração. O Google trata esses dados como informações pessoais de acordo com a nossa Política de Privacidade.
Além disso, os usuários podem desativar o recurso de backup de dados nas configurações de backup do sistema Android. Quando o usuário desativa o backup, o Android Backup Service exclui todos os dados de backup salvos. O usuário pode ativar novamente o backup no dispositivo, mas o Android Backup Service não restaurará os dados excluídos anteriormente.