Usługa kopii zapasowej Androida umożliwia tworzenie kopii zapasowych danych w chmurze i ich przywracanie w aplikacji na Androida. Podczas operacji tworzenia kopii zapasowej danych klucz-wartość dane kopii zapasowej aplikacji są przekazywane do mechanizmu przesyłania kopii zapasowej urządzenia. Jeśli urządzenie korzysta z domyślny transport kopii zapasowych Google, wówczas dane będą przekazywane do kopii zapasowej Androida. Usługa archiwizacji.
Każdy użytkownik aplikacji może mieć maksymalnie 5 MB danych. Przechowywanie danych jest bezpłatne tworzyć kopię zapasową danych.
Przegląd opcji tworzenia kopii zapasowych w Androidzie i wskazówki dotyczące danych tworzyć i przywracać kopie zapasowe, zapoznaj się z sekcją Kopia zapasowa danych .
Wdrożenie kopii zapasowej par klucz-wartość
Aby utworzyć kopię zapasową danych aplikacji, musisz wdrożyć agenta kopii zapasowej. Twój agent kopii zapasowej jest wywoływany przez menedżera kopii zapasowych zarówno podczas tworzenia kopii zapasowej, jak i przywracania.
Aby wdrożyć agenta zapasowego, musisz:
Zadeklaruj agenta kopii zapasowej w pliku manifestu za pomocą atrybutu
android:backupAgent
.Zdefiniuj agenta zapasowego, wykonując jedną z tych czynności:
-
Zajęcia
BackupAgent
to główny interfejs, za pomocą którego aplikacja komunikuje się z Menedżer kopii zapasowych. Jeśli rozszerzysz tę klasę bezpośrednio, musisz zastąpić metodyonBackup()
ionRestore()
, aby obsługiwać operacje tworzenia kopii zapasowych i przywracania danych. -
BackupAgentHelper
zapewnia wygodny kod wokół klasyBackupAgent
, do zminimalizowania ilości kodu do napisania. WBackupAgentHelper
, musisz użyć co najmniej 1 obiektu pomocniczego, który automatycznie tworzyć i przywracać kopie zapasowe określonych typów danych, dzięki czemu unikniesz Trzeba zaimplementowaćonBackup()
ionRestore()
. Jeśli nie potrzebujesz pełnej kontroli nad kopiami zapasowymi aplikacji, zalecamy używanieBackupAgentHelper
do zarządzania kopiami zapasowymi aplikacji.Android udostępnia obecnie pomocnicze narzędzia do tworzenia kopii zapasowych, które umożliwiają tworzenie kopii zapasowych i przywracanie kompletnych plików z
SharedPreferences
oraz wewnętrznego miejsca na dane.
-
Zadeklarowanie agenta zapasowego w pliku manifestu
Gdy zdecydujesz się na nazwę klasy dla agenta zapasowego, zadeklaruj ją w manifeście za pomocą atrybutu android:backupAgent
w tagu <application>
.
Na przykład:
<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>
W celu obsługi starszych urządzeń zalecamy dodanie klucza interfejsu API <meta-data>
do pliku manifestu Androida. Usługa Android Backup Service nie wymaga już klucza usługi, ale niektóre starsze urządzenia mogą nadal sprawdzać klucz podczas tworzenia kopii zapasowej. Ustaw android:name
na com.google.android.backup.api_key
, a
android:value
do unused
.
android:restoreAnyVersion
przyjmuje wartość logiczną wskazującą, czy chcesz przywrócić aplikację
niezależnie od bieżącej wersji aplikacji w porównaniu z wersją
przy tworzeniu kopii zapasowej. Wartością domyślną jest false
. Więcej informacji znajdziesz w artykule Sprawdzanie wersji danych do przywrócenia.
Rozszerzenie BackupAgentHelper
Aby to zrobić, utwórz agenta kopii zapasowej za pomocą BackupAgentHelper
tworzyć kopie zapasowe pełnych plików z usługi SharedPreferences
lub pamięci wewnętrznej.
Utworzenie agenta kopii zapasowej za pomocą BackupAgentHelper
wymaga znacznie mniej kodu niż rozszerzenie BackupAgent
, ponieważ nie musisz implementować onBackup()
ani onRestore()
.
Implementacja BackupAgentHelper
musi korzystać z co najmniej 1 asystenta zapasowego.
Asystent kopii zapasowej to wyspecjalizowany komponent, do którego przywołuje się w usłudze BackupAgentHelper
wykonywania operacji tworzenia i przywracania kopii zapasowych określonego typu danych.
Platforma Android udostępnia obecnie 2 różne aplikacje pomocnicze:
SharedPreferencesBackupHelper
aby utworzyć kopię zapasowąSharedPreferences
plików.FileBackupHelper
do tyłu pobierania plików z pamięci wewnętrznej.
W elementach BackupAgentHelper
możesz uwzględnić wiele elementów pomocniczych, ale dla każdego typu danych potrzebny jest tylko 1 element pomocniczy. Oznacza to, że jeśli masz kilka
SharedPreferences
plików, potrzebujesz tylko jednego
SharedPreferencesBackupHelper
W przypadku każdego pomocnika, którego chcesz dodać do BackupAgentHelper
, musisz wykonać te czynności w ramach metody onCreate()
:
- Utwórz instancję odpowiedniej klasy pomocniczej. W konstruktorze klasy musisz określić pliki, których kopię zapasową chcesz utworzyć.
- Zadzwoń do nas
addHelper()
aby dodać pomocnik do urządzeniaBackupAgentHelper
.
W poniższych sekcjach opisano, jak utworzyć agenta zapasowego za pomocą każdego z z dostępnymi pomocnikami.
Tworzenie kopii zapasowej SharedPreferences
Podczas tworzenia instancji SharedPreferencesBackupHelper
musisz dołączyć parametr
nazwy co najmniej jednego pliku SharedPreferences
.
Aby na przykład utworzyć kopię zapasową pliku SharedPreferences
o nazwie user_preferences
,
pełny agent kopii zapasowej przy użyciu BackupAgentHelper
wygląda tak:
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
zawiera cały kod niezbędny do utworzenia kopii zapasowej
przywrócić plik SharedPreferences
.
Gdy Menedżer kopii zapasowej wywoła onBackup()
i onRestore()
,
BackupAgentHelper
wezwa pomocników, aby utworzyć i przywrócić kopię zapasową danych
określonych plików.
Tworzenie kopii zapasowych innych plików
Podczas tworzenia instancji FileBackupHelper
musisz podać nazwę jednego lub
w pamięci wewnętrznej aplikacji, zgodnie z ustawieniami
getFilesDir()
czyli w tym samym miejscu,
openFileOutput()
zapisuje pliki.
Na przykład, aby utworzyć kopię zapasową 2 plików o nazwach scores
i stats
, agent kopii zapasowej korzystający z BackupAgentHelper
będzie wyglądać tak:
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
zawiera cały kod niezbędny do utworzenia kopii zapasowej i przywrócenia danych
zapisane w pamięci wewnętrznej aplikacji.
Odczytywanie i zapisywanie plików w pamięci wewnętrznej nie jest bezpieczne w wąskim kontekście wątku. Aby mieć pewność, że agent kopii zapasowej nie odczyta ani nie zapisze plików jednocześnie z działaniami, należy używać zsynchronizowanych instrukcji za każdym razem, gdy wykonujesz odczyt lub zapis. Na przykład w każdej czynności, w której odczytujesz i zapisujesz plik, musisz użyć obiektu jako blokady wewnętrznej dla instrukcji zsynchronizowanych:
Kotlin
// Object for intrinsic lock companion object { val sDataLock = Any() }
Java
// Object for intrinsic lock static final Object sDataLock = new Object();
Następnie utwórz zsynchronizowaną instrukcję z tą blokadą przy każdym odczytywaniu lub zapisie pliki. Oto na przykład zsynchronizowane instrukcja zapisywania najnowszego wyniku w grze do pliku:
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"); }
Instrukcje odczytu należy synchronizować przy użyciu tej samej blokady.
Następnie w BackupAgentHelper
musisz zastąpić zasady onBackup()
i
onRestore()
, aby zsynchronizować operacje tworzenia i przywracania kopii zapasowych z tym samym
blokady. Opisane powyżej pole MyFileBackupAgent
wymaga:
następujące metody:
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); } }
Przedłużenie agenta kopii zapasowej
Większość aplikacji nie musi rozszerzać bezpośrednio klasy BackupAgent
, ale powinna rozszerzaćBackupAgentHelper
, aby korzystać z wbudowanych klas pomocniczych, które automatycznie tworzą kopie zapasowe plików i je przywracają.
Możesz jednak bezpośrednio rozszerzyć dostęp do BackupAgent
, aby:
- Wersja formatu danych. Jeśli na przykład spodziewasz się, że konieczne będzie zmienić format, w którym zapisywane są dane aplikacji, można utworzyć kopię zapasową, do sprawdzenia wersji aplikacji podczas przywracania wszelkie niezbędne zgodności działają, jeśli wersja na urządzeniu jest inna niż w kopii zapasowej. Więcej informacji znajdziesz w artykule Sprawdzanie wersji danych do przywracania.
- Określ części danych, które mają być zapisywane w kopii zapasowej. Zamiast tworzyć kopię zapasową całego pliku, możesz określić, które części danych mają zostać skopiowane i jak mają zostać przywrócone na urządzenie. Pomaga to też w zarządzaniu różnymi wersjami, ponieważ dane odczytuje się i zapisze jako unikalne elementy, a nie jako kompletne pliki.
- Utwórz kopię zapasową danych w bazie danych. Jeśli masz bazę danych SQLite, którą chcesz przywrócić, gdy użytkownik ponownie zainstaluje aplikację, musisz utworzyć niestandardową funkcję
BackupAgent
, która odczytuje odpowiednie dane podczas operacji tworzenia kopii zapasowej, a następnie utworzy tabelę i wstawi dane podczas operacji przywracania.
Jeśli nie musisz wykonywać żadnej z powyższych czynności i chcesz utworzyć kopię zapasową
pełne pliki z usługi SharedPreferences
lub pamięci wewnętrznej, patrz Przedłużanie
BackupAgentHelper
.
Wymagane metody
Podczas tworzenia BackupAgent
musisz zaimplementować te metody wywołania zwrotnego:
onBackup()
- Menedżer kopii zapasowych wywołuje tę metodę po przesłaniu prośby Kopia zapasowa. Ta metoda odczytuje dane aplikacji z urządzenia i przekazać do Menedżera kopii zapasowych dane, których kopie zapasowe chcesz utworzyć. opisane w artykule Tworzenie kopii zapasowej.
onRestore()
Menedżer kopii zapasowych wywołuje tę metodę podczas operacji przywracania. Ta metoda udostępnia kopię zapasową danych, dzięki której aplikacja może przywrócić jak opisano w sekcji Przywracanie danych.
System wywołuje tę metodę, aby przywrócić dane kopii zapasowej, gdy użytkownik ponownie instaluje Twoją aplikację, ale aplikacja może też poprosić o przywróć.
Utwórz kopię zapasową
Żądanie kopii zapasowej nie powoduje natychmiastowego wywołania metody onBackup()
. Zamiast tego Menedżer kopii zapasowych czeka odpowiedni czas, a potem tworzy kopie zapasowe wszystkich aplikacji, które poprosiły o kopię zapasową od czasu ostatniej kopii zapasowej. W tym momencie musisz przekazać dane aplikacji do Menedżera kopii zapasowych, aby można je było zapisać w magazynie w chmurze.
Tylko menedżer kopii zapasowych może wywołać metodę onBackup()
agenta kopii zapasowej. Za każdym razem, gdy dane aplikacji ulegną zmianie i chcesz utworzyć kopię zapasową, musisz poprosić o wykonanie operacji tworzenia kopii zapasowej, wywołując funkcję dataChanged()
.
Więcej informacji znajdziesz w artykule Wymaganie utworzenia kopii zapasowej.
Wskazówka: podczas tworzenia aplikacji możesz uruchomić natychmiastowe tworzenie kopii zapasowej w Menedżerze kopii zapasowych za pomocą narzędzia bmgr
.
Gdy Menedżer kopii zapasowych wywołuje metodę onBackup()
, przekazuje 3 parametry:
oldState
- Otwarta, tylko do odczytu
ParcelFileDescriptor
wskazuje do ostatniego stanu kopii zapasowej udostępnionego przez aplikację. To nie są dane kopii zapasowej z chmury, ale jest lokalną reprezentacją danych, których kopia zapasowa została utworzona czas ostatniego wywołania funkcjionBackup()
, zgodnie z definicją zawartą w funkcjinewState
lub zonRestore()
onRestore()
omawiamy w następnej sekcji. PonieważonBackup()
nie pozwala na odczytywanie istniejących danych kopii zapasowej w chmurze, możesz użyć tej lokalnej reprezentacji, aby określić, czy Twoje dane zmieniły się od czasu ostatniej kopii zapasowej. data
- Obiekt
BackupDataOutput
, który służy do przesyłania danych kopii zapasowej do Menedżera kopii zapasowych. newState
- Otwarty, do odczytu i zapisu
ParcelFileDescriptor
wskazujący plik, w którym musi zapisać dane dostarczone przez Ciebie dodata
. O może być tak prosta jak sygnatura czasowa ostatniej modyfikacji pliku. Ten obiekt jest zwracany jakooldState
podczas następnego wywołania przez menedżera kopii zapasowej metodyonBackup()
. Jeśli nie zapiszesz danych kopii zapasowej w usłudzenewState
, a przy następnym wywołaniu Menedżera kopii zapasowejoldState
wskaże pusty plikonBackup()
Za pomocą tych parametrów zaimplementuj metodę onBackup()
, aby:
Sprawdź, czy Twoje dane zmieniły się od czasu ostatniej kopii zapasowej, porównując dane z kopii zapasowej
oldState
z bieżącymi danymi. Sposób odczytywania danych w usłudzeoldState
zależy od sposób, w jaki zostało ono wysłane do użytkownikanewState
(patrz krok 3). Najprostszym sposobem rejestrowania stanu pliku jest użycie sygnatury czasowej ostatniej modyfikacji. Przykład: Aby odczytać i porównać sygnaturę czasową z domenyoldState
: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 }
Jeśli nic się nie zmieniło i nie musisz tworzyć kopii zapasowej, przejdź do kroku 3.
Jeśli Twoje dane uległy zmianie w porównaniu z
oldState
, zapisz bieżące dane wdata
, aby utworzyć ich kopię zapasową w chmurze.Każdy fragment danych musisz zapisać jako encję w
BackupDataOutput
. An encja to spłaszczony rekord binarny identyfikowany przez unikalny klucz ciągu znaków. Dlatego zestaw danych, którego kopię zapasową tworzysz, to teoretycznie zbiór par klucz-wartość.Aby dodać encję do zbioru danych kopii zapasowej, musisz:
Zadzwoń do nas
writeEntityHeader()
, przekazując w niej unikalny klucz ciągu znaków dla danych, które zamierzasz zapisać, oraz rozmiaru danych.Wywołaj funkcję
writeEntityData()
, przekazując bufor bajtów zawierający dane i liczbę bajtów do zapisania z bufora, która powinna być zgodna z rozmiarem przekazanym do funkcjiwriteEntityHeader()
.
Na przykład w poniższym kodzie niektóre dane są spłaszczone do postaci strumienia bajtów, zapisuje go w pojedynczej jednostce:
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);
Wykonaj te czynności w przypadku każdego elementu danych, którego kopię zapasową chcesz utworzyć. Sposób dzielenia zależy od Ciebie. Możesz użyć nawet tylko 1 elementu.
Niezależnie od tego, czy wykonasz kopię zapasową (w kroku 2), zapisz reprezentacje bieżących danych w pliku
newState
ParcelFileDescriptor
. Menedżer kopii zapasowych przechowuje ten obiekt lokalnie jako reprezentację danych, które są obecnie kopiowane. Gdy następnym razem wywoła się funkcjaoldState
, przekaże Ci ją jakooldState
, aby umożliwić Ci określenie, czy potrzebna jest kolejna kopia zapasowa (w tym celu wykonasz krok 1). Jeśli nie zapiszesz bieżącego stanu danych do tego pliku, poleoldState
będzie puste podczas następnego wywołania zwrotnego.W poniższym przykładzie zapisywane są bieżące dane w pliku
newState
przy użyciu sygnatury czasowej ostatniej zmiany pliku: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);
Przywracanie
Gdy nadejdzie czas przywracania danych aplikacji, Menedżer kopii zapasowej wywołuje metodę onRestore()
skryptu kopii zapasowej. Po wywołaniu tej metody Menedżer kopii zapasowych
dostarcza kopię zapasową danych, by móc ją przywrócić na urządzeniu.
Tylko menedżer kopii zapasowych może wywołać funkcję onRestore()
(co odbywa się automatycznie).
gdy system instaluje aplikację i znajduje dane w kopii zapasowej.
Gdy Menedżer kopii zapasowych wywołuje metodę onRestore()
, przekazuje 3 parametry:
data
- Obiekt
BackupDataInput
, który umożliwia odczytywanie danych kopii zapasowej. appVersionCode
- Liczba całkowita określająca wartość
android:versionCode
w pliku manifestu. Możesz go użyć do sprawdzenia bieżącej wersji aplikacji i określenia, czy format danych jest zgodny. Więcej informacji o używaniu tej funkcji do obsługi różnych wersji danych do przywracania znajdziesz w artykule Sprawdzanie wersji danych do przywracania. newState
- Otwarty plik
ParcelFileDescriptor
z dostępem do odczytu i zapisu, który wskazuje plik, do którego musisz zapisać końcowy stan kopii zapasowej podany w plikudata
. Ten obiekt jest zwracany jakooldState
przy następnym wywołaniu funkcjionBackup()
. Przypomnij sobie, musisz również napisać ten sam obiektnewState
w funkcjionBackup()
wywołanie zwrotne – można tu też sprawdzić, czy obiektoldState
przypisany do argumentu MetodaonBackup()
jest prawidłowa nawet wtedy, gdy funkcjaonBackup()
zostanie wywołana po raz pierwszy po urządzenie zostało przywrócone.
W implementacji funkcji onRestore()
należy wywołać funkcję readNextHeader()
w funkcji data
, aby przejść przez wszystkie elementy w zbiorze danych. Dla każdej jednostki
wykonaj te czynności:
- Pobierz klucz encji za pomocą
getKey()
Porównaj klucz elementu z listą znanych wartości kluczy, które powinny być zadeklarowane jako statyczne końcowe ciągi znaków w klasie
BackupAgent
. Gdy klucz pasuje do jednego ze znanych ciągów kluczowych, wprowadź wyrażenie do instrukcji, aby je wyodrębnić dane jednostki i zapisz je na urządzeniu:- Pobierz rozmiar danych encji za pomocą:
getDataSize()
i utworzyć tablicę bajtów o tym rozmiarze. - Wywołaj funkcję
readEntityData()
i przekaż jej tablicę bajtów, do której mają trafić dane, oraz określ przesunięcie początkowe i rozmiar do odczytu. - Tablica bajtów jest teraz pełna. Odczytywanie danych i zapisywanie ich na urządzeniu w dowolny sposób.
- Pobierz rozmiar danych encji za pomocą:
Po odczytaniu i zapisaniu danych z powrotem na urządzeniu zapisz stan do parametru
newState
tak samo jak podczasonBackup()
Oto jak możesz przywrócić dane z kopii zapasowej zgodnie z przykładem w w poprzedniej sekcji:
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); }
W tym przykładzie parametr appVersionCode
przekazany do strony onRestore()
to nie
. Może być on jednak przydatny, jeśli zdecydujesz się wykonać kopię zapasową
gdy wersja aplikacji została przeniesiona do poprzedniej wersji (np.
użytkownik zmienił wersję aplikacji z 1.5 na 1.0). Więcej informacji znajdziesz w następnej sekcji.
Sprawdzanie wersji przywracania danych
Gdy Menedżer kopii zapasowej zapisuje dane w chmurze, automatycznie uwzględnia wersję aplikacji zdefiniowaną przez atrybut android:versionCode
w pliku manifestu. Zanim Menedżer kopii zapasowych wywoła kopię zapasową
aby przywrócić dane, sprawdza android:versionCode
zainstalowanej aplikacji i porównuje ją z wartością zarejestrowaną w zbiorze danych przywracania. Jeśli wersja zapisana w zbiorze danych do przywracania jest nowsza niż wersja aplikacji na urządzeniu, oznacza to, że użytkownik usunął aplikację. W takim przypadku Menedżer kopii zapasowych przerwie operację przywracania aplikacji i nie wywoła metody onRestore()
, ponieważ zbiór danych do przywracania jest uważany za bezużyteczny w przypadku starszej wersji.
Możesz zastąpić to działanie za pomocą atrybutu android:restoreAnyVersion
.
Ustaw ten atrybut na true
, aby wskazać, że chcesz przywrócić aplikację
bez względu na wersję zestawu przywracania. Wartością domyślną jest false
. Jeśli
ustaw tę wartość na true
, Menedżer kopii zapasowych zignoruje
android:versionCode
i we wszystkich przypadkach wywołaj metodę onRestore()
. W tym celu możesz ręcznie sprawdzić różnice w wersji metody onRestore()
i podjąć odpowiednie kroki, aby zapewnić zgodność danych, jeśli wersje się różnią.
Aby ułatwić obsługę różnych wersji podczas operacji przywracania, metoda onRestore()
przekazuje kod wersji zawarty w zbiorze danych do przywracania jako parametr appVersionCode
. Następnie możesz zapytać o kod wersji bieżącej aplikacji za pomocą pola PackageInfo.versionCode
. Na przykład:
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; }
Następnie porównaj wartość version
uzyskaną z PackageInfo
z wartością appVersionCode
przekazaną do funkcji onRestore()
.
Poproś o kopię zapasową
W każdej chwili możesz poprosić o utworzenie kopii zapasowej, dzwoniąc pod numer dataChanged()
. Ta metoda powiadamia Menedżera kopii zapasowych, że chcesz utworzyć kopię zapasową danych za pomocą swojego agenta kopii zapasowej. Menedżer kopii zapasowych wywołuje metodę agenta kopii zapasowej
onBackup()
w przyszłości. Zazwyczaj należy żądać tworzenia kopii zapasowej za każdym razem, gdy dane ulegają zmianie (np. gdy użytkownik zmienia ustawienia aplikacji, których kopię zapasową chcesz utworzyć). Jeśli przed tym, jak Menedżer kopii zapasowych poprosi o kopię zapasową, zadzwonisz do dataChanged()
kilka razy, Twój pracownik obsługi klienta nadal otrzyma tylko 1 wywołanie do onBackup()
.
Prośba o przywrócenie
Nie musisz prosić o przywrócenie aplikacji podczas normalnego działania aplikacji. . System automatycznie sprawdza, czy istnieją dane kopii zapasowej, i przywraca je po zainstalowaniu aplikacji.
Migracja do Automatycznej kopii zapasowej
Możesz przełączyć aplikację na kopie zapasowe pełnych danych, ustawiając wartość android:fullBackupOnly
na true
w elemencie <application>
w pliku manifestu. Jeśli aplikacja działa na urządzeniu z Androidem 5.1 (poziom interfejsu API 22) lub starszym, ignoruje tę wartość w pliku manifestu i nadal wykonuje kopie zapasowe kluczy i wartości. Gdy aplikacja działa na urządzeniu z Androidem 6.0 (poziom interfejsu API 23) lub nowszym, wykonuje automatyczne kopie zapasowe zamiast kopii zapasowych kluczy i wartości.
Prywatność użytkowników
W Google doskonale zdajemy sobie sprawę z zaufania, jakim obdarzają nas użytkownicy, odpowiedzialnością za ochronę użytkowników prywatności. Google bezpiecznie przesyła dane kopii zapasowej do serwerów Google i z nich w celu udostępniania funkcji tworzenia kopii zapasowych i przywracania danych. Google traktuje te dane jako dane osobowe zgodnie z Polityka prywatności.
Użytkownicy mogą też wyłączyć funkcję tworzenia kopii zapasowych w ustawieniach kopii zapasowej systemu Android. Gdy użytkownik wyłączy kopię zapasową, usługa Android Backup Service usunie wszystkie zapisane dane kopii zapasowej. Użytkownik może ponownie włączyć kopię zapasową na urządzeniu, ale usługa kopii zapasowej Androida nie przywróci wcześniej usuniętych danych.