Google berkomitmen untuk mendorong terwujudnya keadilan ras bagi komunitas Kulit Hitam. Lihat caranya.

Mencadangkan key-value pair dengan Android Backup Service

Catatan: Untuk sebagian besar aplikasi, Auto Backup harus digunakan untuk mengimplementasikan pencadangan dan pemulihan. Aplikasi hanya dapat mengimplementasikan Pencadangan Otomatis atau pencadangan nilai kunci, bukan keduanya. Pencadangan Otomatis tidak memerlukan kode dan akan mencadangkan seluruh file, sementara pencadangan nilai kunci mengharuskan Anda menulis kode untuk menentukan konten cadangan secara eksplisit dalam bentuk key-value pair.

Sebelumnya, developer mendaftarkan aplikasi untuk mendapatkan kunci layanan. Anda tidak perlu lagi mendaftarkan aplikasi untuk pencadangan nilai kunci.

Android Backup Service menyediakan pencadangan dan pemulihan penyimpanan cloud untuk data nilai kunci di aplikasi Android. Selama operasi pencadangan nilai kunci, data pencadangan aplikasi diteruskan ke Backup Transport perangkat. Jika perangkat menggunakan Google Backup Transport default, data akan diteruskan ke Android Backup Service untuk pengarsipan.

Jumlah data dibatasi hingga 5 MB per pengguna aplikasi dan penyimpanan data cadangan dapat dilakukan secara gratis.

Untuk ringkasan mengenai opsi pencadangan Android dan panduan terkait data apa saja yang sebaiknya Anda cadangkan dan pulihkan, baca ringkasan pencadangan data.

Mengimplementasikan pencadangan nilai kunci

Untuk mencadangkan data aplikasi, Anda perlu mengimplementasikan agen pencadangan. Agen pencadangan dipanggil oleh Pengelola Pencadangan selama proses pencadangan dan pemulihan.

Untuk mengimplementasikan agen pencadangan, Anda harus:

  1. Mendeklarasikan agen pencadangan dalam file manifes dengan atribut android:backupAgent.
  2. Menentukan agen pencadangan baik dengan:
    1. Memperluas BackupAgent

      Class BackupAgent menyediakan antarmuka terpusat yang digunakan aplikasi Anda untuk berkomunikasi dengan Pengelola Pencadangan. Jika Anda memperluas class ini secara langsung, Anda harus mengganti onBackup() dan onRestore() untuk menangani operasi pencadangan dan pemulihan untuk data Anda.

    2. Atau

    3. Memperluas BackupAgentHelper

      Class BackupAgentHelper menyediakan wrapper yang cocok dengan class BackupAgent, yang meminimalkan jumlah kode yang harus Anda tulis. Di BackupAgentHelper, Anda harus menggunakan satu atau beberapa objek "helper", yang otomatis mencadangkan dan memulihkan jenis data tertentu, sehingga Anda tidak perlu mengimplementasikan onBackup() dan onRestore(). Kecuali jika Anda memerlukan kontrol penuh atas cadangan aplikasi, sebaiknya gunakan BackupAgentHelper untuk menangani cadangan aplikasi Anda.

      Saat ini, Android menyediakan helper pencadangan yang akan mencadangkan dan memulihkan seluruh file dari SharedPreferences dan penyimpanan internal.

Mendeklarasikan agen pencadangan dalam manifes

Ini adalah langkah termudah, setelah memutuskan nama class untuk agen pencadangan, deklarasikan agen pencadangan dalam manifes dengan atribut android:backupAgent dalam tag <application>.

Contoh:

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

Untuk mendukung perangkat yang lebih lama, sebaiknya tambahkan kunci API <meta-data> ke file manifes Android. Android Backup Service tidak lagi memerlukan kunci layanan, tetapi beberapa perangkat yang lebih lama mungkin masih memeriksa kunci saat melakukan pencadangan. Tetapkan android:name ke "com.google.android.backup.api_key" dan android:value ke "unused".

Atribut lain yang dapat Anda gunakan adalah android:restoreAnyVersion. Atribut ini memerlukan nilai boolean untuk menunjukkan apakah Anda ingin memulihkan data aplikasi terlepas dari versi aplikasi saat ini dibandingkan dengan versi yang membuat data cadangan. (Nilai defaultnya adalah "false".) Untuk informasi selengkapnya, lihat Memeriksa versi data pemulihan.

Android Backup Service

Google menyediakan Backup Transport dengan Android Backup Service untuk sebagian besar perangkat Android yang menjalankan Android 2.2 atau yang lebih baru.

Catatan: Backup Transport yang disediakan oleh Android Backup Service tidak dijamin tersedia di semua perangkat Android yang mendukung pencadangan. Sebagian perangkat mungkin mendukung pencadangan menggunakan transport berbeda, sebagian perangkat mungkin tidak mendukung pencadangan sama sekali, dan aplikasi tidak dapat mengetahui transport yang digunakan di perangkat.

Memperluas BackupAgentHelper

Anda harus membuat agen pencadangan menggunakan BackupAgentHelper jika ingin mencadangkan semua file (baik dari SharedPreferences atau penyimpanan internal). Membuat agen pencadangan dengan BackupAgentHelper membutuhkan kode yang jauh lebih sedikit daripada memperluas BackupAgent, karena Anda tidak perlu mengimplementasikan onBackup() dan onRestore().

Penerapan BackupAgentHelper harus menggunakan satu atau beberapa helper pencadangan. Helper pencadangan adalah komponen khusus yang digunakan BackupAgentHelper untuk melakukan operasi pencadangan dan pemulihan untuk jenis data tertentu. Framework Android saat ini menyediakan dua helper yang berbeda:

Anda dapat menyertakan beberapa helper di BackupAgentHelper, tetapi hanya satu helper yang diperlukan untuk setiap jenis data. Artinya, jika Anda memiliki beberapa file SharedPreferences, Anda hanya memerlukan satu SharedPreferencesBackupHelper.

Untuk setiap helper yang ingin ditambahkan ke BackupAgentHelper, Anda harus melakukan hal berikut selama metode onCreate():

  1. Membuat instance class helper yang diinginkan. Dalam constructor class, Anda harus menentukan file tertentu yang ingin dicadangkan.
  2. Panggil addHelper() untuk menambahkan helper ke BackupAgentHelper Anda.

Bagian berikut menjelaskan cara membuat agen pencadangan menggunakan masing-masing helper yang tersedia.

Mencadangkan SharedPreferences

Saat membuat instance SharedPreferencesBackupHelper, Anda harus menyertakan nama satu atau beberapa file SharedPreferences.

Misalnya, untuk mencadangkan file SharedPreferences bernama user_preferences, agen pencadangan lengkap menggunakan BackupAgentHelper dan terlihat seperti ini:

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

Selesai. SharedPreferencesBackupHelper menyertakan semua kode yang diperlukan untuk mencadangkan dan memulihkan file SharedPreferences.

Saat Pengelola Pencadangan memanggil onBackup() dan onRestore(), BackupAgentHelper akan memanggil helper cadangan Anda untuk melakukan pencadangan dan pemulihan file tertentu.

Catatan: Metode SharedPreferences aman bagi thread, sehingga Anda dapat dengan aman membaca dan menulis file preferensi yang dibagikan dari agen pencadangan dan aktivitas lainnya.

Mencadangkan file lainnya

Saat membuat instance FileBackupHelper, Anda harus menyertakan nama satu atau beberapa file yang disimpan ke penyimpanan internal aplikasi Anda (seperti yang ditentukan oleh getFilesDir(), yakni lokasi yang sama tempat openFileOutput() menulis file).

Misalnya, untuk mencadangkan dua file bernama scores dan stats, agen pencadangan menggunakan BackupAgentHelper, dan terlihat seperti ini:

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 menyertakan semua kode yang diperlukan untuk mencadangkan dan memulihkan file yang disimpan ke penyimpanan internal aplikasi Anda.

Namun, membaca dan menulis file pada penyimpanan internal tidak aman bagi thread. Untuk memastikan bahwa agen pencadangan tidak membaca atau menulis file bersamaan dengan aktivitas Anda, Anda harus menggunakan pernyataan tersinkron setiap kali Anda melakukan proses baca atau tulis. Misalnya, di Aktivitas mana pun tempat Anda membaca dan menulis file, Anda memerlukan objek untuk digunakan sebagai kunci intrinsik untuk pernyataan tersinkron:

Kotlin

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

Java

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

Lalu buat laporan tersinkron dengan kunci ini setiap kali Anda membaca atau menulis file. Misalnya, berikut adalah pernyataan tersinkron untuk menulis skor terbaru dalam game ke 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");
}

Anda harus menyinkronkan pernyataan baca dengan kunci yang sama.

Lalu, di BackupAgentHelper, Anda harus mengganti onBackup() dan onRestore() untuk menyinkronkan operasi pencadangan dan pemulihan dengan kunci intrinsik yang sama. Misalnya, contoh MyFileBackupAgent di atas memerlukan metode berikut:

Kotlin

@Throws(IOException::class)
override fun onBackup(
        oldState: ParcelFileDescriptor,
        data: BackupDataOutput,
        newState: ParcelFileDescriptor
) {
    // Hold the lock while the FileBackupHelper performs backup
    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 backup
    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);
    }
}

Hanya ini yang Anda butuhkan untuk mencadangkan dan memulihkan data dengan BackupAgentHelper.

Memperluas BackupAgent

Sebagian besar aplikasi tidak perlu memperluas class BackupAgent secara langsung, tetapi perlu memperluas BackupAgentHelper untuk memanfaatkan class helper bawaan yang otomatis mencadangkan dan memulihkan file Anda. Namun, Anda mungkin harus memperluas BackupAgent secara langsung jika Anda diperlukan:

  • Menetapkan versi format data Anda. Misalnya, jika Anda mengantisipasi kebutuhan untuk memperbaiki format yang digunakan untuk menulis data aplikasi, Anda dapat membuat agen pencadangan untuk memeriksa versi aplikasi selama operasi pemulihan dan melakukan pekerjaan kompatibilitas apa pun yang diperlukan jika versi pada perangkat berbeda dengan data cadangan. Untuk informasi selengkapnya, lihat Memeriksa versi data pemulihan.
  • Daripada mencadangkan seluruh file, Anda dapat menentukan bagian data yang perlu dicadangkan dan bagaimana nantinya setiap bagian dipulihkan ke perangkat. (Hal ini juga dapat membantu Anda mengelola versi yang berbeda, karena Anda membaca dan menulis data sebagai entitas unik, bukan satu file utuh).
  • Mencadangkan data di database. Jika memiliki database SQLite yang ingin dipulihkan saat pengguna menginstal ulang aplikasi, Anda perlu membuat BackupAgent kustom yang membaca data yang sesuai selama operasi pencadangan, lalu buat tabel dan masukkan data selama operasi pemulihan.

Jika Anda tidak perlu melakukan salah satu tugas di atas dan ingin mencadangkan seluruh file dari SharedPreferences atau penyimpanan internal, lihat Memperluas BackupAgentHelper.

Metode yang diperlukan

Saat membuat BackupAgent, Anda harus mengimplementasikan metode callback berikut:

onBackup()
Pengelola Pencadangan memanggil metode ini setelah Anda meminta pencadangan. Dalam metode ini, Anda membaca data aplikasi dari perangkat dan meneruskan data yang ingin dicadangkan ke Pengelola Pencadangan, seperti yang dijelaskan di bawah ini dalam Melakukan pencadangan.
onRestore()
Pengelola Pencadangan memanggil metode ini selama operasi pemulihan. Metode ini mengirimkan data cadangan, yang dapat digunakan aplikasi Anda untuk memulihkan status sebelumnya, seperti yang dijelaskan di bawah ini pada Melakukan pemulihan.

Sistem memanggil metode ini untuk memulihkan data cadangan apa pun saat pengguna menginstal ulang aplikasi Anda, tetapi aplikasi Anda juga dapat meminta pemulihan.

Melakukan pencadangan

Jika waktu untuk mencadangkan data aplikasi Anda sudah tiba, Pengelola Pencadangan akan memanggil metode onBackup() Anda. Inilah saatnya untuk memberikan data aplikasi ke Pengelola Pencadangan agar dapat disimpan ke penyimpanan cloud.

Hanya Pengelola Pencadangan yang dapat memanggil metode onBackup() agen pencadangan Anda. Setiap kali data aplikasi berubah dan Anda ingin melakukan pencadangan, Anda harus meminta operasi pencadangan dengan memanggil dataChanged() (lihat Meminta pencadangan untuk informasi selengkapnya). Permintaan pencadangan tidak menghasilkan panggilan langsung ke metode onBackup() Anda. Sebaliknya, Pengelola Pencadangan menunggu waktu yang tepat, lalu melakukan pencadangan untuk semua aplikasi yang telah meminta pencadangan sejak pencadangan terakhir dilakukan.

Tips: Saat mengembangkan aplikasi, Anda dapat memulai operasi pencadangan langsung dari Pengelola Pencadangan dengan alat bmgr.

Saat Pengelola Pencadangan memanggil metode onBackup() Anda, metode ini akan meneruskan tiga parameter:

oldState
ParcelFileDescriptor hanya baca terbuka yang mengarah ke status pencadangan terakhir yang disediakan aplikasi Anda. Ini bukan data backup dari penyimpanan cloud, tetapi representasi lokal dari data yang dicadangkan terakhir kali saat onBackup() dipanggil (seperti yang ditetapkan oleh newState, di bawah, atau dari onRestore()— ini dibahas selengkapnya di bagian berikutnya). Karena onBackup() tidak mengizinkan Anda membaca data cadangan yang ada di penyimpanan cloud, Anda dapat menggunakan representasi lokal ini untuk menentukan apakah data Anda telah berubah sejak pencadangan terakhir.
data
Objek BackupDataOutput, yang Anda gunakan untuk mengirimkan data cadangan ke Pengelola Pencadangan.
newState
ParcelFileDescriptor baca/tulis terbuka yang mengarah ke file tempat Anda harus menulis representasi dari data yang dikirim ke data (representasi boleh sederhana seperti stempel waktu yang terakhir diubah untuk file Anda). Objek ini ditampilkan sebagai oldState saat Pengelola Pencadangan memanggil metode onBackup() Anda lagi. Jika Anda tidak menulis data cadangan ke newState, oldState akan mengarah ke file kosong saat Pengelola Pencadangan memanggil onBackup() lagi.

Untuk menggunakan parameter ini, Anda harus mengimplementasikan metode onBackup() untuk melakukan hal berikut:

  1. Memeriksa apakah data Anda telah berubah sejak pencadangan terakhir dengan membandingkan oldState dengan data Anda saat ini. Cara membaca data dalam oldState tergantung pada bagaimana Anda menulisnya ke newState (lihat langkah 3). Cara termudah untuk mencatat status file adalah dengan stempel waktu terakhir diubahnya. Berikut adalah contoh cara membaca dan membandingkan stempel waktu dari 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
    }
    
    

    Jika tidak ada yang berubah dan Anda tidak perlu melakukan pencadangan, lanjutkan ke langkah 3.

  2. Jika data Anda berubah, dibandingkan dengan oldState, tulis data saat ini ke data untuk mencadangkannya ke penyimpanan cloud.

    Anda harus menulis setiap bagian data sebagai "entitas" dalam BackupDataOutput. Entitas adalah rekaman data biner yang disederhanakan yang diidentifikasi dengan string kunci unik. Jadi, set data yang Anda cadangkan secara konseptual adalah kumpulan key-value pair.

    Untuk menambahkan entitas ke set data cadangan, Anda harus:

    1. Memanggil writeEntityHeader(), meneruskan kunci string unik untuk data yang akan Anda tulis beserta ukuran datanya.
    2. Memanggil writeEntityData(), meneruskan buffer byte yang berisi data dan jumlah byte yang akan ditulis dari buffer (yang seharusnya sesuai dengan ukuran yang diteruskan ke writeEntityHeader()).

    Misalnya, kode berikut menyederhanakan beberapa data menjadi aliran byte dan menulisnya menjadi satu entitas:

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

    Lakukan ini untuk setiap bagian data yang ingin Anda cadangkan. Anda dapat menentukan cara membagi data menjadi entitas (dan Anda dapat menggunakan satu entitas saja).

  3. Baik Anda melakukan pencadangan atau tidak (dalam langkah 2), tulis representasi data saat ini ke newState ParcelFileDescriptor. Pengelola Pencadangan mempertahankan objek ini secara lokal sebagai representasi data yang saat ini sedang dicadangkan. Pengelola Pencadangan mengembalikan objek tersebut sebagai oldState saat Anda memanggil onBackup(), sehingga Anda dapat menentukan apakah pencadangan lainnya diperlukan (sebagaimana dijelaskan di langkah 1). Jika Anda tidak menulis status data saat ini ke file ini, oldState ini akan kosong selama callback berikutnya.

    Contoh berikut menyimpan representasi data saat ini ke newState menggunakan stempel waktu terakhir diubah 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);
    
    

Perhatian: Jika data aplikasi Anda disimpan ke file, pastikan Anda menggunakan pernyataan tersinkron saat mengakses file agar agen pencadangan tidak membaca file saat Aktivitas di aplikasi Anda sedang menulis file.

Melakukan pemulihan

Jika waktu untuk memulihkan data aplikasi Anda sudah tiba, Pengelola Pencadangan memanggil metode onRestore() agen pencadangan Anda. Saat memanggil metode ini, Pengelola Pencadangan akan mengirim data cadangan Anda, sehingga Anda dapat memulihkannya ke perangkat.

Hanya Pengelola Pencadangan yang dapat memanggil onRestore(), yang terjadi secara otomatis saat sistem menginstal aplikasi Anda dan menemukan data cadangan yang ada.

Catatan: Saat mengembangkan aplikasi, Anda juga dapat meminta operasi pemulihan dengan alat bmgr .

Saat Pengelola Pencadangan memanggil metode onRestore() Anda, metode ini akan meneruskan tiga parameter:

data
BackupDataInput, yang memungkinkan Anda membaca data cadangan.
appVersionCode
Bilangan bulat yang merepresentasikan nilai atribut manifes android:versionCode aplikasi Anda, seperti saat data ini dicadangkan. Anda dapat menggunakannya untuk memeriksa versi aplikasi saat ini dan menentukan apakah format data tersebut kompatibel. Untuk informasi selengkapnya tentang cara menggunakan ini untuk menangani versi data pemulihan yang berbeda, lihat bagian di bawah ini tentang Memeriksa versi data pemulihan.
newState
ParcelFileDescriptor baca/tulis terbuka yang mengarah ke file tempat Anda harus menulis status pencadangan terakhir yang diberikan dengan data. Objek ini ditampilkan sebagai oldState saat Anda memanggil onBackup(). Pastikan untuk menulis objek newState yang sama di callback onBackup()—menuliskannya di sini memastikan bahwa objek oldState yang diberikan kepada onBackup() valid bahkan saat onBackup() pertama kali dipanggil setelah perangkat dipulihkan.

Saat mengimplementasikan onRestore(), Anda harus memanggil readNextHeader() pada data untuk mengiterasi semua entitas dalam set data. Untuk setiap entitas yang ditemukan, lakukan hal berikut:

  1. Dapatkan kunci entitas dengan getKey().
  2. Bandingkan kunci entitas dengan daftar nilai kunci yang diketahui yang harus Anda deklarasikan sebagai string final statis dalam class BackupAgent. Apabila kunci cocok dengan salah satu string utama yang diketahui, masukkan ke dalam pernyataan untuk mengekstrak data entitasnya lalu simpan ke perangkat:
    1. Dapatkan ukuran data entitas dengan getDataSize() dan buat array byte dari ukuran tersebut.
    2. Panggil readEntityData() dan teruskan array byte, tempat tujuan data, lalu tentukan offset awal dan ukuran untuk dibaca.
    3. Array byte Anda sekarang penuh dan Anda dapat membaca data dan menulisnya ke perangkat sesuai keinginan Anda.
  3. Setelah membaca dan menulis data kembali ke perangkat, tulis status data Anda ke parameter newState, sama seperti yang Anda lakukan selama onBackup().

Berikut adalah contoh cara memulihkan data yang dicadangkan dengan contoh di bagian sebelumnya:

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

Dalam contoh ini, parameter appVersionCode yang diteruskan ke onRestore() tidak digunakan. Namun, Anda dapat menggunakannya jika Anda memilih untuk melakukan pencadangan saat versi aplikasi pengguna benar-benar telah di-downgrade (misalnya, pengguna beralih dari versi 1.5 aplikasi Anda ke versi 1.0). Untuk informasi selengkapnya, lihat bagian Memeriksa versi data pemulihan.

Memeriksa versi data pemulihan

Saat Pengelola pencadangan menyimpan data Anda ke penyimpanan cloud, versi aplikasi Anda akan otomatis disertakan, seperti yang ditentukan oleh atribut android:versionCode file manifes Anda. Sebelum Pengelola Pencadangan memanggil agen pencadangan untuk memulihkan data, Pengelola Pencadangan akan melihat android:versionCode aplikasi yang diinstal dan membandingkannya dengan nilai yang dicatat dalam set data pemulihan. Jika versi yang dicatat dalam set data pemulihan adalah versi yang lebih baru dari versi aplikasi di perangkat, maka pengguna telah men-downgrade versi aplikasinya. Dalam kasus ini, Pengelola Pencadangan akan membatalkan operasi pemulihan untuk aplikasi Anda dan tidak akan memanggil metode onRestore(), karena set pemulihan dianggap tidak dapat digunakan untuk versi yang lebih lama.

Anda dapat mengganti perilaku ini dengan atribut android:restoreAnyVersion. Atribut ini dapat berupa "true" atau "false" untuk menunjukkan apakah Anda ingin memulihkan aplikasi terlepas dari versi set pemulihan. Nilai defaultnya adalah "false". Jika Anda menetapkan ini ke "true", Pengelola Pencadangan akan mengabaikan android:versionCode dan memanggil metode onRestore() Anda dalam kasus apa pun. Dengan demikian, Anda dapat memeriksa perbedaan versi secara manual di metode onRestore() dan melakukan hal apa pun yang diperlukan untuk membuat data kompatibel jika versinya bertentangan.

Untuk membantu menangani versi yang berbeda selama operasi pemulihan, metode onRestore() meneruskan kode versi yang disertakan dengan set data pemulihan sebagai parameter appVersionCode. Lalu Anda dapat mengkueri kode versi aplikasi saat ini dengan kolom PackageInfo.versionCode. Contoh:

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

Kemudian cukup bandingkan version yang diperoleh dari PackageInfo ke appVersionCode yang diteruskan ke onRestore().

Perhatian: Pastikan Anda memahami konsekuensi menetapkan android:restoreAnyVersion ke "true" untuk aplikasi Anda. Jika setiap versi aplikasi Anda yang mendukung pencadangan tidak mempertimbangkan dengan tepat variasi format data Anda selama onRestore(), data di perangkat tersebut dapat disimpan dalam format yang tidak kompatibel dengan versi yang saat ini diinstal di perangkat.

Meminta pencadangan

Anda dapat meminta operasi pencadangan kapan saja dengan memanggil dataChanged(). Metode ini memberi tahu Pengelola Pencadangan bahwa Anda ingin mencadangkan data menggunakan agen pencadangan. Kemudian Pengelola Pencadangan akan memanggil metode onBackup() agen pencadangan Anda pada waktu yang tepat di masa mendatang. Biasanya, Anda harus meminta pencadangan setiap kali data Anda berubah (misalnya saat pengguna mengubah preferensi aplikasi yang ingin Anda cadangkan). Jika Anda memanggil dataChanged() beberapa kali secara berurutan, sebelum Pengelola Pencadangan meminta pencadangan dari agen Anda, agen Anda tetap menerima satu panggilan saja untuk onBackup().

Catatan: Saat mengembangkan aplikasi, Anda dapat meminta pencadangan dan memulai operasi pencadangan langsung dengan alat bmgr .

Meminta pemulihan

Selama aplikasi Anda berfungsi dengan normal, Anda tidak perlu meminta operasi pemulihan. Sistem secara otomatis memeriksa data backup dan melakukan pemulihan saat aplikasi Anda diinstal.

Catatan: Saat mengembangkan aplikasi, Anda dapat meminta operasi pemulihan dengan alat bmgr .

Bermigrasi ke pencadangan otomatis

Anda dapat melakukan transisi aplikasi ke pencadangan data menyeluruh dengan menetapkan android:fullBackupOnly ke true dalam elemen <application> di file manifes. Saat dijalankan di perangkat yang menggunakan Android 5.1 (API level 22) atau lebih yang rendah, aplikasi Anda mengabaikan nilai ini dalam manifes, dan tetap melakukan pencadangan nilai kunci. Saat dijalankan di perangkat yang menggunakan Android 6.0 (API level 23) atau lebih yang tinggi, aplikasi Anda melakukan pencadangan otomatis, bukan pencadangan nilai kunci.

Privasi pengguna

Di Google, kami sangat menyadari kepercayaan pengguna yang telah diberikan kepada kami dan kami bertanggung jawab untuk melindungi privasi pengguna. Google secara aman mengirim data cadangan ke dan dari server Google untuk memberikan fitur pencadangan dan pemulihan. Google memperlakukan data ini sebagai informasi pribadi sesuai dengan Kebijakan Privasi Google.

Selain itu, pengguna dapat menonaktifkan fungsi pencadangan data melalui setelan cadangan sistem Android. Saat pengguna menonaktifkan pencadangan, Android Backup Service akan menghapus semua data cadangan yang disimpan. Pengguna dapat mengaktifkan kembali pencadangan di perangkat, tetapi Android Backup Service tidak akan memulihkan data yang telah dihapus sebelumnya.