Android Backup Service позволяет создавать резервные копии данных типа "ключ-значение" в облачном хранилище и восстанавливать их в приложении Android. При создании резервной копии данных типа "ключ-значение" данные резервной копии приложения передаются в транспорт резервного копирования устройства. Если на устройстве используется стандартный транспорт резервного копирования Google, данные передаются в Android Backup Service для архивации.
Объем данных ограничен 5 МБ на пользователя приложения. Плата за хранение резервных копий не взимается.
Обзор вариантов резервного копирования в Android и рекомендации по выбору данных для резервного копирования и восстановления приведены в статье Обзор резервного копирования данных.
Как реализовать резервное копирование пар "ключ-значение"
Чтобы создать резервную копию данных приложения, необходимо реализовать агент резервного копирования. Менеджер резервного копирования вызывает агент резервного копирования как во время резервного копирования, так и во время восстановления.
Чтобы реализовать агент резервного копирования, необходимо:
Объявите агент резервного копирования в файле манифеста с помощью атрибута
android:backupAgent.Определите агент резервного копирования, выполнив одно из следующих действий:
Увеличение длины трека "
BackupAgent"Класс
BackupAgentпредоставляет центральный интерфейс, который ваше приложение использует для связи с Менеджером резервного копирования. Если вы расширяете этот класс напрямую, вам нужно переопределить методыonBackup()иonRestore(), чтобы управлять операциями резервного копирования и восстановления данных.Увеличение длины трека "
BackupAgentHelper"Класс
BackupAgentHelperпредставляет собой удобную оболочку для классаBackupAgent, которая позволяет минимизировать объем кода. ВBackupAgentHelperнеобходимо использовать один или несколько вспомогательных объектов, которые автоматически создают резервные копии определенных типов данных и восстанавливают их. Это позволяет не реализовывать методыonBackup()иonRestore(). Если вам не нужен полный контроль над резервными копиями приложения, рекомендуем использоватьBackupAgentHelper.В настоящее время в Android есть помощники по резервному копированию, которые создают резервные копии и восстанавливают файлы из
SharedPreferencesи внутреннего хранилища.
Объявите агент резервного копирования в манифесте
Выбрав название класса для агента резервного копирования, объявите его в манифесте с помощью атрибута android:backupAgent в теге <application>.
Пример:
<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>
Чтобы обеспечить поддержку более старых устройств, рекомендуем добавить ключ API <meta-data> в файл манифеста Android. Для работы Android Backup Service больше не требуется ключ сервиса, но некоторые старые устройства могут по-прежнему проверять его наличие при резервном копировании. Задайте для параметра android:name значение com.google.android.backup.api_key, а для параметра android:value – значение unused.
Атрибут android:restoreAnyVersion принимает логическое значение, которое указывает, нужно ли восстанавливать данные приложения независимо от того, какая версия приложения используется сейчас и какая использовалась при создании резервной копии. Значение по умолчанию: false. Подробнее о том, как проверить версию данных для восстановления…
Расширение BackupAgentHelper
Если вы хотите создать резервную копию всех файлов из SharedPreferences или внутренней памяти, используйте BackupAgentHelper.
При создании агента резервного копирования с помощью BackupAgentHelper требуется гораздо меньше кода, чем при расширении BackupAgent, поскольку вам не нужно реализовывать onBackup() и onRestore().
В вашей реализации BackupAgentHelper должен использоваться один или несколько помощников резервного копирования.
Помощник по резервному копированию – это специализированный компонент, который BackupAgentHelper вызывает для выполнения операций резервного копирования и восстановления данных определенного типа. В настоящее время фреймворк Android предоставляет два разных помощника:
SharedPreferencesBackupHelperдля резервного копированияSharedPreferencesфайлов.FileBackupHelper, чтобы создать резервные копии файлов из внутренней памяти.
В BackupAgentHelper можно добавить несколько помощников, но для каждого типа данных нужен только один. Если у вас несколько файлов SharedPreferences, вам нужен только один файл SharedPreferencesBackupHelper.
Для каждого помощника, которого вы хотите добавить в BackupAgentHelper, необходимо выполнить следующие действия в методе onCreate():
- Создайте экземпляр нужного вспомогательного класса. В конструкторе класса необходимо указать файлы, резервные копии которых вы хотите создать.
- Вызовите метод
addHelper(), чтобы добавить вспомогательный класс вBackupAgentHelper.
В следующих разделах описывается, как создать агента резервного копирования с помощью каждого из доступных помощников.
Резервное копирование SharedPreferences
При создании экземпляра SharedPreferencesBackupHelper необходимо указать название одного или нескольких файлов SharedPreferences.
Например, для резервного копирования файла SharedPreferences с именем user_preferences полный агент резервного копирования с использованием BackupAgentHelper выглядит следующим образом:
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 содержит весь код, необходимый для резервного копирования и восстановления файла SharedPreferences.
Когда Менеджер резервного копирования вызывает onBackup() и onRestore(), BackupAgentHelper вызывает помощников резервного копирования, чтобы создать резервные копии указанных файлов и восстановить их.
Резервное копирование других файлов
При создании экземпляра FileBackupHelper необходимо указать название одного или нескольких файлов, сохраненных во внутреннем хранилище приложения, как указано в getFilesDir(). Это то же место, куда openFileOutput() записывает файлы.
Например, чтобы создать резервную копию двух файлов с названиями scores и stats, агент резервного копирования, использующий BackupAgentHelper, выглядит следующим образом:
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 содержит весь код, необходимый для резервного копирования и восстановления файлов, сохраненных во внутреннем хранилище приложения.
Однако чтение и запись файлов во внутренней памяти не являются потокобезопасными. Чтобы агент резервного копирования не читал и не записывал файлы одновременно с вашими действиями, вы должны использовать синхронизированные операторы каждый раз, когда выполняете чтение или запись. Например, в любом действии, где вы читаете и записываете файл, вам нужен объект, который будет использоваться в качестве внутренней блокировки для синхронизированных операторов:
Kotlin
// Object for intrinsic lock companion object { val sDataLock = Any() }
Java
// Object for intrinsic lock static final Object sDataLock = new Object();
Затем создайте синхронизированную инструкцию с этой блокировкой для каждого случая чтения или записи файлов. Например, вот синхронизированная инструкция для записи последнего счета в игре в файл:
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"); }
Операторы чтения должны быть синхронизированы с той же блокировкой.
Затем в BackupAgentHelper необходимо переопределить onBackup() и onRestore(), чтобы синхронизировать операции резервного копирования и восстановления с помощью одной и той же внутренней блокировки. Например, для приведенного выше примера MyFileBackupAgent требуются следующие методы:
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
В большинстве приложений не нужно расширять класс BackupAgent напрямую. Вместо этого следует расширить BackupAgentHelper, чтобы использовать встроенные вспомогательные классы, которые автоматически создают резервные копии файлов и восстанавливают их.
Однако вы можете расширить BackupAgent напрямую, чтобы:
- Указывайте версию формата данных. Например, если вы планируете изменить формат записи данных приложения, вы можете создать агент резервного копирования, который будет проверять версию приложения во время восстановления и выполнять необходимые действия по обеспечению совместимости, если версия на устройстве отличается от версии в резервной копии. Подробнее о том, как проверить версию данных для восстановления…
- Укажите, какие данные нужно скопировать. Вместо резервного копирования всего файла вы можете указать, какие части данных нужно скопировать и как каждая часть затем восстанавливается на устройстве. Это также может помочь вам управлять разными версиями, поскольку вы читаете и записываете свои данные как уникальные объекты, а не как полные файлы.
- Создание резервной копии данных в базе данных. Если у вас есть база данных SQLite, которую вы хотите восстанавливать при переустановке приложения, вам нужно создать собственный класс
BackupAgent, который будет считывать нужные данные во время резервного копирования, а затем создавать таблицу и вставлять данные во время восстановления.
Если вам не нужно выполнять ни одну из перечисленных выше задач и вы хотите создать резервную копию всех файлов из SharedPreferences или внутреннего хранилища, ознакомьтесь с разделом Расширение BackupAgentHelper.
Обязательные методы
При создании BackupAgent необходимо реализовать следующие методы обратного вызова:
onBackup()- Менеджер резервного копирования вызывает этот метод после того, как вы запросите резервное копирование. При этом вы считываете данные приложения с устройства и передаете те, для которых хотите создать резервную копию, в Менеджер резервного копирования, как описано в разделе Создание резервной копии.
onRestore()Менеджер резервного копирования вызывает этот метод во время операции восстановления. Этот метод передает резервные данные, которые приложение может использовать для восстановления своего прежнего состояния, как описано в разделе Выполнение восстановления.
Система вызывает этот метод, чтобы восстановить данные из резервной копии, когда пользователь переустанавливает приложение. Однако приложение также может запросить восстановление.
Как создать резервную копию
Запрос на резервное копирование не приводит к немедленному вызову метода onBackup(). Вместо этого он ждет подходящего момента, а затем выполняет резервное копирование для всех приложений, которые запрашивали его с момента последнего резервного копирования. В этот момент вы должны предоставить данные приложения Менеджеру резервного копирования, чтобы он мог сохранить их в облачном хранилище.
Только Backup Manager может вызывать метод onBackup() вашего агента резервного копирования. Каждый раз, когда данные приложения меняются и вы хотите создать резервную копию, необходимо запрашивать операцию резервного копирования, вызывая dataChanged().
Подробнее о том, как запросить резервную копию…
Совет. При разработке приложения вы можете запустить немедленное резервное копирование из Менеджера резервного копирования с помощью инструмента bmgr.
Когда Backup Manager вызывает метод onBackup(), он передает три параметра:
oldState- Открытый объект
ParcelFileDescriptor, доступный только для чтения и указывающий на последнее состояние резервной копии, предоставленное вашим приложением. Это не данные резервной копии из облачного хранилища, а локальное представление данных, резервная копия которых была создана при последнем вызовеonBackup(), как определено вnewStateилиonRestore().onRestore()рассматривается в следующем разделе. ПосколькуonBackup()не позволяет читать существующие данные резервной копии в облачном хранилище, вы можете использовать это локальное представление, чтобы определить, изменились ли ваши данные с момента последнего резервного копирования. data- Объект
BackupDataOutput, который используется для передачи резервных копий данных в Backup Manager. newState- Открытый объект
ParcelFileDescriptorс правами на чтение и запись, указывающий на файл, в который нужно записать представление данных, переданных вdata. В качестве представления может использоваться временная метка последнего изменения файла. Этот объект возвращается в видеoldStateпри следующем вызове методаonBackup()менеджером резервного копирования. Если вы не запишете резервные данные вnewState, то при следующем вызовеonBackup()Менеджером резервного копированияoldStateбудет указывать на пустой файл.
Используя эти параметры, реализуйте метод onBackup(), чтобы выполнить следующие действия:
Проверьте, изменились ли ваши данные с момента последнего резервного копирования, сравнив
oldStateс текущими данными. Способ чтения данных вoldStateзависит от того, как вы изначально записали их вnewState(см. шаг 3). Проще всего зафиксировать состояние файла с помощью временной метки последнего изменения. Например, вот как можно прочитать и сравнить временную метку изoldState: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 }
Если ничего не изменилось и вам не нужно создавать резервную копию, перейдите к шагу 3.
Если ваши данные изменились по сравнению с
oldState, запишите текущие данные вdata, чтобы создать резервную копию в облачном хранилище.Каждый фрагмент данных должен быть записан как объект в
BackupDataOutput. Объект – это плоская запись двоичных данных, которая идентифицируется уникальной строкой ключа. Таким образом, набор данных, для которого вы создаете резервную копию, концептуально представляет собой набор пар "ключ-значение".Чтобы добавить объект в набор данных резервной копии, выполните следующие действия:
Вызовите метод
writeEntityHeader(), передав уникальный строковый ключ для данных, которые вы собираетесь записать, и размер данных.Вызовите
writeEntityData(), передав байтовый буфер, содержащий ваши данные, и количество байтов, которые нужно записать из буфера. Это количество должно соответствовать размеру, переданному вwriteEntityHeader().
Например, следующий код преобразует данные в поток байтов и записывает их в один объект:
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);
Повторите это действие для всех данных, которые хотите скопировать. Как вы разделите свои данные на сущности, зависит от вас. Вы можете использовать даже один объект.
Независимо от того, создаете ли вы резервную копию (на шаге 2), запишите представление текущих данных в
newStateParcelFileDescriptor. Менеджер резервного копирования сохраняет этот объект локально как представление данных, для которых в настоящее время создана резервная копия. При следующем вызовеonBackup()он передает вам это значение в видеoldState, чтобы вы могли определить, нужно ли создавать резервную копию, как описано на шаге 1. Если вы не запишете текущее состояние данных в этот файл, то при следующем обратном вызовеoldStateбудет пустым.В следующем примере представление текущих данных сохраняется в
newStateс использованием временной метки последнего изменения файла: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);
Как восстановить данные
Когда приходит время восстановить данные приложения, менеджер резервного копирования вызывает метод onRestore() агента резервного копирования. При вызове этого метода Менеджер резервного копирования передает данные резервной копии, чтобы вы могли восстановить их на устройстве.
Метод onRestore() может вызывать только менеджер резервного копирования. Это происходит автоматически, когда система устанавливает приложение и находит существующие резервные копии данных.
Когда Backup Manager вызывает метод onRestore(), он передает три параметра:
data- Объект
BackupDataInput, который позволяет читать данные резервной копии. appVersionCode- Целое число, представляющее значение атрибута манифеста
android:versionCodeвашего приложения на момент резервного копирования данных. Вы можете использовать его, чтобы проверить текущую версию приложения и определить, совместим ли формат данных. Подробнее о том, как использовать этот метод для обработки разных версий данных восстановления, рассказывается в разделе Проверка версии данных восстановления. newState- Открытый объект
ParcelFileDescriptor, указывающий на файл, в который нужно записать конечное состояние резервной копии, предоставленное с помощьюdata. Этот объект возвращается какoldStateпри следующем вызовеonBackup(). Напоминаем, что вы также должны записать тот же объектnewStateв обратный вызовonBackup(). Это гарантирует, что объектoldState, переданный вonBackup(), будет действителен даже при первом вызовеonBackup()после восстановления устройства.
В реализации onRestore() необходимо вызвать readNextHeader() для data, чтобы перебрать все объекты в наборе данных. Для каждого найденного объекта выполните следующие действия:
- Получите ключ объекта с помощью
getKey(). Сравните ключ объекта со списком известных значений ключей, которые вы должны были объявить как статические конечные строки в классе
BackupAgent. Если ключ совпадает с одной из известных строк ключа, введите оператор, чтобы извлечь данные объекта и сохранить их на устройстве:- Получите размер данных объекта с помощью
getDataSize()и создайте массив байтов этого размера. - Вызовите
readEntityData()и передайте ему массив байтов, в который будут помещены данные, а также укажите начальное смещение и размер для чтения. - Теперь массив байтов заполнен. Прочитайте данные и запишите их на устройство любым удобным способом.
- Получите размер данных объекта с помощью
После того как вы прочитаете и запишете данные обратно на устройство, запишите состояние данных в параметр
newStateтак же, как вы делаете это во времяonBackup().
Например, вот как можно восстановить данные, резервная копия которых была создана в примере из предыдущего раздела:
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); }
В этом примере параметр appVersionCode, переданный в onRestore(), не используется. Однако вы можете использовать его, если решили выполнить резервное копирование, когда версия приложения пользователя фактически откатилась назад (например, пользователь перешел с версии 1.5 вашего приложения на 1.0). Подробная информация приведена в следующем разделе.
Проверьте версию восстанавливаемых данных
Когда менеджер резервного копирования сохраняет данные в облачном хранилище, он автоматически включает версию приложения, указанную в атрибуте android:versionCode файла манифеста. Прежде чем вызвать агент резервного копирования для восстановления данных, Менеджер резервного копирования проверяет значение android:versionCode установленного приложения и сравнивает его со значением, записанным в наборе данных для восстановления. Если версия, записанная в наборе данных для восстановления, новее версии приложения на устройстве, значит пользователь установил более раннюю версию приложения. В этом случае Менеджер резервного копирования прервет операцию восстановления для вашего приложения и не вызовет метод onRestore(), поскольку набор данных для восстановления считается бессмысленным для более старой версии.
Это поведение можно переопределить с помощью атрибута android:restoreAnyVersion.
Задайте для этого атрибута значение true, чтобы указать, что вы хотите восстановить приложение независимо от версии набора для восстановления. Значение по умолчанию: false. Если задать для этого атрибута значение true, то менеджер резервного копирования будет игнорировать android:versionCode и во всех случаях вызывать метод onRestore(). Это позволит вам вручную проверить разницу между версиями в методе onRestore() и предпринять необходимые действия, чтобы обеспечить совместимость данных, если версии не совпадают.
Чтобы помочь вам обрабатывать разные версии во время операции восстановления, метод onRestore() передает вам код версии, включенный в набор данных восстановления, в качестве параметра appVersionCode. Затем вы можете запросить код версии текущего приложения с помощью поля PackageInfo.versionCode. Пример:
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; }
Затем сравните значение version, полученное из PackageInfo, со значением appVersionCode, переданным в onRestore().
Запросить резервную копию
Вы можете в любой момент запросить резервное копирование, вызвав метод dataChanged(). Этот метод уведомляет Менеджер резервного копирования о том, что вы хотите создать резервную копию данных с помощью агента резервного копирования. Затем Менеджер резервного копирования вызывает метод onBackup() агента резервного копирования. Как правило, запрашивать резервное копирование следует каждый раз, когда меняются данные (например, когда пользователь меняет настройки приложения, которые вы хотите сохранить). Если вы вызовете dataChanged() несколько раз до того, как Менеджер резервного копирования запросит резервную копию у вашего агента, агент все равно получит только один вызов onBackup().
Как запросить восстановление
В обычных условиях запрашивать восстановление не требуется. При установке приложения система автоматически проверяет наличие резервных копий и выполняет восстановление.
Переход на автоматическое копирование в облако
Чтобы перейти на полное резервное копирование, задайте для атрибута android:fullBackupOnly значение true в элементе <application> файла манифеста. На устройствах с Android 5.1 (уровень API 22) или более ранней версией приложение игнорирует это значение в манифесте и продолжает выполнять резервное копирование типа "ключ-значение". На устройствах с Android 6.0 (уровень API 23) или более поздней версии приложение выполняет автоматическое копирование в облако вместо резервного копирования пар "ключ-значение".
конфиденциальность пользователя;
Компания Google высоко ценит доверие со стороны пользователей и в полной мере осознает свою ответственность за защиту их конфиденциальности. Чтобы вы могли создавать резервные копии и восстанавливать данные, Google безопасно передает их на свои серверы и обратно. Google считает эти данные личной информацией в соответствии с Политикой конфиденциальности Google.
Кроме того, пользователи могут отключить резервное копирование данных в настройках системы Android. Если пользователь отключает резервное копирование, Android Backup Service удаляет все сохраненные данные. Пользователь может снова включить резервное копирование на устройстве, но Android Backup Service не восстановит удаленные данные.