Anahtar/değer çiftlerini Android Backup Service ile yedekleme

Android Yedekleme Hizmeti, Android uygulamanızdaki anahtar/değer verileri için bulut depolama alanı yedekleme ve geri yükleme hizmeti sunar. Anahtar/değer yedekleme işlemi sırasında uygulamanın yedekleme verileri cihazın yedekleme aktarımına iletilir. Cihaz, varsayılan Google yedekleme aktarımını kullanıyorsa veriler arşivlenmek üzere Android Yedekleme Hizmeti'ne iletilir.

Veriler, uygulamanızın her kullanıcısı için 5 MB ile sınırlıdır. Yedekleme verilerinin depolanması için herhangi bir ücret alınmaz.

Android'in yedekleme seçeneklerine genel bakış ve hangi verileri yedekleyip geri yüklemeniz gerektiğiyle ilgili rehberlik için Veri yedeklemeye genel bakış başlıklı makaleyi inceleyin.

Anahtar/değer çifti yedeklemesini uygulama

Uygulama verilerinizi yedeklemek için bir yedekleme aracısı uygulamanız gerekir. Yedekleme aracınız, hem yedekleme hem de geri yükleme sırasında Yedekleme Yöneticisi tarafından çağrılır.

Yedekleme aracısı uygulamak için:

  1. Yedekleme aracınızı manifest dosyanızda android:backupAgent özelliğiyle beyan edin.

  2. Aşağıdakilerden birini yaparak yedek temsilci tanımlayın:

    • BackupAgent uzatılıyor

      BackupAgent sınıfı, uygulamanızın Yedekleme Yöneticisi ile iletişim kurmak için kullandığı merkezi arayüzü sağlar. Bu sınıfı doğrudan genişletirseniz verilerinizin yedekleme ve geri yükleme işlemlerini gerçekleştirmek için onBackup() ve onRestore() yöntemlerini geçersiz kılmanız gerekir.

    • BackupAgentHelper uzatılıyor

      BackupAgentHelper sınıfı, BackupAgent sınıfı için kullanışlı bir sarmalayıcı sağlayarak yazmanız gereken kod miktarını en aza indirir. BackupAgentHelper uygulamanızda, belirli veri türlerini otomatik olarak yedekleyen ve geri yükleyen bir veya daha fazla yardımcı nesne kullanmanız gerekir. Böylece onBackup() ve onRestore() yöntemlerini uygulamanız gerekmez. Uygulamanızın yedeklemeleri üzerinde tam kontrole ihtiyacınız yoksa uygulamanızın yedeklemelerini yönetmek için BackupAgentHelper kullanmanızı öneririz.

      Android şu anda SharedPreferences ve dahili depolama alanındaki dosyaların tamamını yedekleyip geri yükleyecek yedekleme yardımcıları sunmaktadır.

Manifestinizde yedekleme aracısını bildirme

Yedekleme aracınızın sınıf adını belirledikten sonra <application> etiketindeki android:backupAgent özelliğini kullanarak manifest dosyanızda bunu beyan edin.

Örneğin:

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

Eski cihazları desteklemek için API anahtarını <meta-data> Android manifest dosyanıza eklemenizi öneririz. Android Backup Service artık hizmet anahtarı gerektirmiyor ancak bazı eski cihazlar yedekleme sırasında anahtar kontrolü yapmaya devam edebilir. android:name değerini com.google.android.backup.api_key, android:value değerini ise unused olarak ayarlayın.

android:restoreAnyVersion özelliği, yedekleme verilerini oluşturan sürüme kıyasla mevcut uygulama sürümünden bağımsız olarak uygulama verilerini geri yüklemek isteyip istemediğinizi belirtmek için bir boole değeri alır. Varsayılan değer: false. Daha fazla bilgi için Veri geri yükleme sürümünü kontrol etme başlıklı makaleyi inceleyin.

BackupAgentHelper'ı genişletme

SharedPreferences veya dahili depolama alanındaki dosyaların tamamını yedeklemek istiyorsanız yedekleme aracınızı BackupAgentHelper kullanarak oluşturmanız gerekir. Yedekleme aracınızı BackupAgentHelper ile oluşturmak, BackupAgent sınıfını genişletmekten çok daha az kod gerektirir. Çünkü onBackup() ve onRestore() yöntemlerini uygulamanız gerekmez.

BackupAgentHelper uygulamanızda bir veya daha fazla yedekleme yardımcısı kullanılmalıdır. Yedekleme yardımcısı, belirli bir veri türü için yedekleme ve geri yükleme işlemlerini gerçekleştirmek üzere BackupAgentHelper tarafından çağrılan özel bir bileşendir. Android çerçevesi şu anda iki farklı yardımcı sunar:

BackupAgentHelper uygulamanıza birden fazla yardımcı ekleyebilirsiniz ancak her veri türü için yalnızca bir yardımcı gerekir. Yani birden fazla SharedPreferences dosyanız varsa yalnızca bir SharedPreferencesBackupHelper dosyasına ihtiyacınız vardır.

BackupAgentHelper uygulamanıza eklemek istediğiniz her yardımcı için onCreate() yönteminiz sırasında aşağıdakileri yapmanız gerekir:

  1. Seçilen yardımcı sınıfın bir örneğini oluşturun. Sınıf oluşturucuda, yedeklemek istediğiniz dosyaları belirtmeniz gerekir.
  2. Yardımcıyı BackupAgentHelper cihazınıza eklemek için addHelper() numaralı telefonu arayın.

Aşağıdaki bölümlerde, mevcut yardımcıların her birini kullanarak yedekleme aracısı oluşturma işlemi açıklanmaktadır.

SharedPreferences'ı yedekleme

Bir SharedPreferencesBackupHelper örneklendirdiğinizde bir veya daha fazla SharedPreferences dosyasının adını eklemeniz gerekir.

Örneğin, user_preferences adlı bir SharedPreferences dosyasını yedeklemek için BackupAgentHelper kullanan eksiksiz bir yedekleme aracısı şu şekilde görünür:

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, bir SharedPreferences dosyasını yedeklemek ve geri yüklemek için gereken tüm kodları içerir.

Yedekleme Yöneticisi onBackup() ve onRestore() yöntemlerini çağırdığında BackupAgentHelper, belirtilen dosyalarınızı yedeklemek ve geri yüklemek için yedekleme yardımcılarınızı çağırır.

Diğer dosyaları yedekleme

Bir FileBackupHelper örneği oluşturduğunuzda, getFilesDir() tarafından belirtildiği gibi uygulamanızın dahili depolama alanına kaydedilen bir veya daha fazla dosyanın adını eklemeniz gerekir. Bu, openFileOutput() tarafından dosyaların yazıldığı konumla aynıdır.

Örneğin, scores ve stats adlı iki dosyayı yedeklemek için BackupAgentHelper kullanan bir yedekleme aracısı şu şekilde görünür:

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, uygulamanızın dahili depolama alanına kaydedilen dosyaları yedeklemek ve geri yüklemek için gereken tüm kodları içerir.

Ancak dahili depolama alanındaki dosyaları okuma ve yazma işlemleri iş parçacığı için güvenli değildir. Yedekleme aracınızın, etkinliklerinizle aynı anda dosyalarınızı okumadığından veya yazmadığından emin olmak için her okuma ya da yazma işlemi gerçekleştirdiğinizde senkronize edilmiş ifadeler kullanmanız gerekir. Örneğin, dosyayı okuyup yazdığınız herhangi bir etkinlikte, senkronize edilmiş ifadeler için iç kilit olarak kullanılacak bir nesneye ihtiyacınız vardır:

Kotlin

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

Java

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

Ardından, dosyaları her okuduğunuzda veya yazdığınızda bu kilitle senkronize bir ifade oluşturun. Örneğin, bir oyundaki en son puanı bir dosyaya yazmak için senkronize edilmiş bir ifade aşağıda verilmiştir:

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

Okuma ifadelerinizi aynı kilitle senkronize etmeniz gerekir.

Ardından, yedekleme ve geri yükleme işlemlerini aynı iç kilit ile senkronize etmek için BackupAgentHelper uygulamanızda onBackup() ve onRestore() yöntemlerini geçersiz kılmanız gerekir. Örneğin, önceki MyFileBackupAgent örneği için aşağıdaki yöntemler gerekir:

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'ı genişletme

Çoğu uygulamanın BackupAgent sınıfını doğrudan genişletmesi gerekmez. Bunun yerine, dosyalarınızı otomatik olarak yedekleyip geri yükleyen yerleşik yardımcı sınıflardan yararlanmak için BackupAgentHelper sınıfını genişletmeleri gerekir. Ancak aşağıdakileri yapmak için BackupAgent sınıfını doğrudan genişletebilirsiniz:

  • Veri biçiminizi sürümlendirin. Örneğin, uygulama verilerinizi yazdığınız biçimi düzeltmeniz gerekeceğini tahmin ediyorsanız geri yükleme işlemi sırasında uygulama sürümünüzü çapraz kontrol etmek ve cihazdaki sürüm yedekleme verilerinden farklıysa gerekli uyumluluk çalışmalarını yapmak için bir yedekleme aracısı oluşturabilirsiniz. Daha fazla bilgi için Geri yükleme verilerinin sürümünü kontrol etme başlıklı makaleyi inceleyin.
  • Verilerin yedeklenecek kısımlarını belirtin. Dosyanın tamamını yedeklemek yerine, yedeklenecek veri bölümlerini ve her bölümün cihaza nasıl geri yükleneceğini belirtebilirsiniz. Bu sayede, verilerinizi tam dosyalar yerine benzersiz varlıklar olarak okuyup yazdığınız için farklı sürümleri de yönetebilirsiniz.
  • Veritabanındaki verileri yedekleme Kullanıcı uygulamanızı yeniden yüklediğinde geri yüklemek istediğiniz bir SQLite veritabanınız varsa yedekleme işlemi sırasında uygun verileri okuyan özel bir BackupAgent oluşturmanız, ardından geri yükleme işlemi sırasında tablonuzu oluşturup verileri eklemeniz gerekir.

Yukarıdaki görevlerden hiçbirini gerçekleştirmeniz gerekmiyorsa ve SharedPreferences veya dahili depolama alanındaki dosyaların tamamını yedeklemek istiyorsanız BackupAgentHelper uygulamasını genişletme başlıklı makaleyi inceleyin.

Gerekli yöntemler

BackupAgent oluşturduğunuzda aşağıdaki geri çağırma yöntemlerini uygulamanız gerekir:

onBackup()
Yedekleme Yöneticisi, siz yedekleme isteğinde bulunduktan sonra bu yöntemi çağırır. Bu yöntemde, uygulama verilerinizi cihazdan okur ve yedeklemek istediğiniz verileri Yedekleme gerçekleştirme bölümünde açıklandığı gibi Yedekleme Yöneticisi'ne iletirsiniz.
onRestore()

Yedekleme Yöneticisi, geri yükleme işlemi sırasında bu yöntemi çağırır. Bu yöntem, uygulamanızın eski durumunu geri yüklemek için kullanabileceği yedek verilerinizi Geri yükleme işlemi gerçekleştirme bölümünde açıklandığı şekilde sunar.

Sistem, kullanıcı uygulamanızı yeniden yüklediğinde yedek verileri geri yüklemek için bu yöntemi çağırır ancak uygulamanız da geri yükleme isteğinde bulunabilir.

Yedekleme yapma

Yedekleme isteği, onBackup() yönteminizin hemen çağrılmasına neden olmaz. Bunun yerine, Yedekleme Yöneticisi uygun bir zamanı bekler ve son yedekleme işleminden sonra yedekleme isteğinde bulunan tüm uygulamalar için yedekleme yapar. Bu noktada, uygulama verilerinizi Yedekleme Yöneticisi'ne sağlamanız gerekir. Böylece veriler bulut depolama alanına kaydedilebilir.

Yalnızca Yedekleme Yöneticisi, yedekleme aracınızın onBackup() yöntemini çağırabilir. Uygulama verileriniz her değiştiğinde ve yedekleme yapmak istediğinizde dataChanged() yöntemini çağırarak yedekleme işlemi isteğinde bulunmanız gerekir. Daha fazla bilgi için Yedekleme isteğinde bulunma başlıklı makaleyi inceleyin.

İpucu: Uygulamanızı geliştirirken bmgr aracını kullanarak Yedekleme Yöneticisi'nden anında yedekleme işlemi başlatabilirsiniz.

Yedekleme Yöneticisi, onBackup() yönteminizi çağırdığında üç parametre iletir:

oldState
Uygulamanız tarafından sağlanan son yedekleme durumunu gösteren, açık ve salt okunur bir ParcelFileDescriptor. Bu, bulut depolama alanındaki yedekleme verileri değil, newState tarafından tanımlandığı şekilde veya onRestore() üzerinden onBackup() son çağrıldığında yedeklenen verilerin yerel bir temsilidir. onRestore() bir sonraki bölümde ele alınmaktadır. onBackup(), bulut depolama alanındaki mevcut yedekleme verilerini okumanıza izin vermediğinden, verilerinizin son yedeklemeden sonra değişip değişmediğini belirlemek için bu yerel temsili kullanabilirsiniz.
data
Yedekleme verilerinizi Yedekleme Yöneticisi'ne göndermek için kullandığınız bir BackupDataOutput nesnesi.
newState
data'ye gönderdiğiniz verilerin bir temsilini yazmanız gereken bir dosyayı işaret eden açık, okuma-yazma özellikli bir ParcelFileDescriptor. Temsil, dosyanızın son değiştirilme zaman damgası olabilir. Bu nesne, Yedekleme Yöneticisi'nin onBackup() yönteminizi bir sonraki çağırışında oldState olarak döndürülür. Yedekleme verilerinizi newState dosyasına yazmazsanız Yedekleme Yöneticisi, onBackup() yöntemini bir sonraki çağırışında oldState boş bir dosyayı işaret eder.

Bu parametreleri kullanarak onBackup() yönteminizi aşağıdaki işlemleri yapacak şekilde uygulayın:

  1. oldState ile mevcut verilerinizi karşılaştırarak son yedeklemeden bu yana verilerinizin değişip değişmediğini kontrol edin. oldState uygulamasında verileri nasıl okuyacağınız, verileri newState uygulamasına nasıl yazdığınıza bağlıdır (3. adıma bakın). Bir dosyanın durumunu kaydetmenin en kolay yolu, son değiştirilme zaman damgasını kullanmaktır. Örneğin, oldState üzerinden bir zaman damgasını şu şekilde okuyabilir ve karşılaştırabilirsiniz:

    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
    }
    

    Hiçbir değişiklik olmadıysa ve yedekleme yapmanız gerekmiyorsa 3. adıma geçin.

  2. Verileriniz oldState ile karşılaştırıldığında değiştiyse bulut depolama alanına yedeklemek için mevcut verileri data konumuna yazın.

    Her veri parçasını BackupDataOutput içinde bir varlık olarak yazmanız gerekir. Varlık, benzersiz bir anahtar dizesiyle tanımlanan düzleştirilmiş bir ikili veri kaydıdır. Bu nedenle, yedeklediğiniz veri kümesi kavramsal olarak bir anahtar/değer çifti kümesidir.

    Yedek veri kümenize bir varlık eklemek için:

    1. Yazacağınız veriler ve veri boyutu için benzersiz bir dize anahtarı ileterek writeEntityHeader() yöntemini çağırın.

    2. Verilerinizi içeren bir bayt arabelleği ve arabellekten yazılacak bayt sayısını (writeEntityHeader() değerine iletilen boyutla eşleşmelidir) ileterek writeEntityData() yöntemini çağırın.

    Örneğin, aşağıdaki kod bazı verileri bir bayt akışına düzleştirir ve tek bir öğeye yazar:

    Kotlin

    val buffer: ByteArray = ByteArrayOutputStream().run {
        DataOutputStream(this).apply {
            writeInt(playerName)
            writeInt(playerScore)
        }
        toByteArray()
    }
    val len: Int = buffer.size
    data.apply {
        writeEntityHeader(TOPSCORE_BACKUP_KEY, len)
        writeEntityData(buffer, len)
    }
    

    Java

    // Create buffer stream and data output stream for our data
    ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
    DataOutputStream outWriter = new DataOutputStream(bufStream);
    // Write structured data
    outWriter.writeUTF(playerName);
    outWriter.writeInt(playerScore);
    // Send the data to the Backup Manager using the BackupDataOutput
    byte[] buffer = bufStream.toByteArray();
    int len = buffer.length;
    data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
    data.writeEntityData(buffer, len);
    

    Yedeklemek istediğiniz her veri parçası için bu işlemi gerçekleştirin. Verilerinizi varlıklara nasıl böleceğiniz size bağlıdır. Yalnızca bir varlık bile kullanabilirsiniz.

  3. Yedekleme yapıp yapmadığınıza bakılmaksızın (2. adımda), mevcut verilerin bir temsilini newState ParcelFileDescriptor içine yazın. Yedekleme Yöneticisi, bu nesneyi yerel olarak saklayarak o anda yedeklenen verileri temsil eder. onBackup() bir sonraki çağrısında bunu size oldState olarak geri iletir. Böylece, 1. adımda açıklandığı gibi başka bir yedeklemenin gerekli olup olmadığını belirleyebilirsiniz. Mevcut veri durumunu bu dosyaya yazmazsanız bir sonraki geri çağırma sırasında oldState boş olur.

    Aşağıdaki örnekte, dosyanın son değiştirilme zaman damgası kullanılarak mevcut verilerin bir temsili newState dosyasına kaydedilir:

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

Geri yükleme işlemi gerçekleştirme

Uygulama verilerinizi geri yükleme zamanı geldiğinde Yedekleme Yöneticisi, yedekleme aracınızın onRestore() yöntemini çağırır. Yedekleme Yöneticisi bu yöntemi çağırdığında, yedekleme verilerinizi cihaza geri yükleyebilmeniz için size iletir.

Yalnızca Yedekleme Yöneticisi onRestore() yöntemini çağırabilir. Bu işlem, sistem uygulamanızı yükleyip mevcut yedekleme verilerini bulduğunda otomatik olarak gerçekleşir.

Yedekleme Yöneticisi, onRestore() yönteminizi çağırdığında üç parametre iletir:

data
Yedekleme verilerinizi okumanıza olanak tanıyan bir BackupDataInput nesnesi.
appVersionCode
Bu veriler yedeklendiğinde uygulamanızın android:versionCode manifest özelliğinin değerini temsil eden bir tam sayı. Bu bilgiyi kullanarak mevcut uygulama sürümünü kontrol edebilir ve veri biçiminin uyumlu olup olmadığını belirleyebilirsiniz. Geri yükleme verilerinin farklı sürümlerini işlemek için bu yöntemi kullanma hakkında daha fazla bilgi edinmek istiyorsanız Geri yükleme verilerinin sürümünü kontrol etme başlıklı makaleyi inceleyin.
newState
data ile sağlanan son yedekleme durumunu yazmanız gereken bir dosyayı işaret eden açık, okuma-yazma özellikli ParcelFileDescriptor. Bu nesne, onBackup() bir sonraki çağrılışında oldState olarak döndürülür. Aynı newState nesnesini onBackup() geri çağırma işlevine de yazmanız gerektiğini unutmayın. Bu işlemi burada da yapmak, cihaz geri yüklendikten sonra onBackup() ilk kez çağrıldığında bile onBackup() işlevine verilen oldState nesnesinin geçerli olmasını sağlar.

onRestore() uygulamanızda, veri kümesindeki tüm varlıklar arasında gezinmek için data üzerinde readNextHeader() yöntemini çağırmanız gerekir. Bulunan her varlık için aşağıdakileri yapın:

  1. getKey() ile varlık anahtarını alın.
  2. Varlık anahtarını, BackupAgent sınıfınızda statik nihai dizeler olarak tanımlamış olmanız gereken bilinen anahtar değerleri listesiyle karşılaştırın. Anahtar, bilinen anahtar dizelerinizden biriyle eşleştiğinde varlık verilerini ayıklamak ve cihaza kaydetmek için bir ifade girin:

    1. getDataSize() ile varlık verilerinin boyutunu alın ve bu boyutta bir bayt dizisi oluşturun.
    2. readEntityData() yöntemini çağırın ve verilerin gideceği bayt dizisini iletin. Ardından, başlangıç ofsetini ve okunacak boyutu belirtin.
    3. Bayt diziniz artık dolu. Verileri okuyun ve istediğiniz şekilde cihaza yazın.
  3. Verilerinizi okuyup cihaza geri yazdıktan sonra, verilerinizin durumunu onBackup() sırasında yaptığınız gibi newState parametresine yazın.

Örneğin, önceki bölümde verilen örnekte yedeklenen verileri şu şekilde geri yükleyebilirsiniz:

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

Bu örnekte, onRestore() işlevine iletilen appVersionCode parametresi kullanılmamaktadır. Ancak kullanıcının uygulama sürümü geriye gittiğinde (örneğin, kullanıcı uygulamanızın 1.5 sürümünden 1.0 sürümüne geçtiğinde) yedekleme yapmayı seçtiyseniz bu özelliği kullanmak isteyebilirsiniz. Daha fazla bilgi için sonraki bölüme bakın.

Geri yükleme verilerinin sürümünü kontrol etme

Yedekleme Yöneticisi, verilerinizi bulut depolama alanına kaydederken uygulamanızın sürümünü otomatik olarak ekler. Bu sürüm, manifesto dosyanızın android:versionCode özelliği tarafından tanımlanır. Yedekleme Yöneticisi, verilerinizi geri yüklemek için yedekleme aracınızı çağırmadan önce yüklü uygulamanın android:versionCode değerine bakar ve bunu geri yükleme veri kümesinde kayıtlı değerle karşılaştırır. Geri yükleme veri kümesinde kayıtlı sürüm, cihazdaki uygulama sürümünden daha yeniyse kullanıcı, uygulamasını eski sürüme geçirmiştir. Bu durumda, geri yükleme kümesi eski bir sürüm için anlamsız kabul edildiğinden Yedekleme Yöneticisi, uygulamanızın geri yükleme işlemini iptal eder ve onRestore() yönteminizi çağırmaz.

android:restoreAnyVersion özelliğini kullanarak bu davranışı geçersiz kılabilirsiniz:

  • false (varsayılan): Geri yükleme veri kümesinde kayıtlı sürüm, cihazdaki uygulama sürümünden daha yeniyse Yedekleme Yöneticisi geri yükleme işlemini iptal eder.
  • true: Yedekleme Yöneticisi, android:versionCode değerini yoksayar ve her durumda onRestore() yönteminizi çağırır. Böylece sürüm farklılıklarını manuel olarak kontrol edebilir ve verileri uyumlu hale getirebilirsiniz.

Geri yükleme işlemi sırasında farklı sürümleri yönetmenize yardımcı olmak için onRestore() yöntemi, geri yükleme veri kümesine dahil edilen sürüm kodunu appVersionCode parametresi olarak iletir. Ardından, PackageInfo.versionCode alanını kullanarak mevcut uygulamanın sürüm kodunu sorgulayabilirsiniz. Örneğin:

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

Ardından, PackageInfo üzerinden alınan version değerini onRestore() yöntemine iletilen appVersionCode değeriyle karşılaştırın.

Yedekleme isteğinde bulunma

dataChanged() yöntemini çağırarak dilediğiniz zaman yedekleme işlemi isteğinde bulunabilirsiniz. Bu yöntem, yedekleme aracınızı kullanarak verilerinizi yedeklemek istediğinizi Yedekleme Yöneticisi'ne bildirir. Yedekleme yöneticisi daha sonra yedekleme aracınızın onBackup() yöntemini çağırır. Genellikle, verileriniz her değiştiğinde (örneğin, kullanıcı yedeklemek istediğiniz bir uygulama tercihini değiştirdiğinde) yedekleme isteğinde bulunmanız gerekir. Yedekleme Yöneticisi, temsilcinizden yedekleme isteğinde bulunmadan önce dataChanged() yöntemini birkaç kez çağırırsanız temsilciniz yine de onBackup() yöntemine yönelik yalnızca bir çağrı alır.

Geri yükleme isteğinde bulunma

Uygulamanızın normal kullanım ömrü boyunca geri yükleme işlemi istemeniz gerekmez. Sistem, yedekleme verilerini otomatik olarak kontrol eder ve uygulamanız yüklendiğinde geri yükleme işlemi gerçekleştirir.

Otomatik Yedekleme'ye geçiş

Manifesto dosyasındaki <application> öğesinde android:fullBackupOnly değerini true olarak ayarlayarak uygulamanızı tam veri yedeklemelerine geçirebilirsiniz. Android 5.1 (API düzeyi 22) veya daha eski bir sürümün yüklü olduğu cihazlarda çalışırken uygulamanız, manifest dosyasındaki bu değeri yoksayar ve anahtar/değer yedeklemeleri yapmaya devam eder. Android 6.0 (API düzeyi 23) veya sonraki sürümlerin yüklü olduğu bir cihazda çalışırken uygulamanız, anahtar/değer çifti yedekleme yerine Otomatik Yedekleme gerçekleştirir.

Kullanıcı gizliliği

Google olarak, kullanıcıların bize duyduğu güvene değer veriyoruz. Kullanıcıların gizliliğini koruma sorumluluğunun bize ait olduğunun farkındayız. Google, yedekleme ve geri yükleme özelliklerini sunmak için yedekleme verilerini Google sunucularına güvenli bir şekilde iletir ve bu sunuculardan alır. Google, bu verileri Google'ın Gizlilik Politikası'na uygun şekilde kişisel bilgi olarak ele alır.

Ayrıca kullanıcılar, Android sisteminin yedekleme ayarlarından veri yedekleme işlevini devre dışı bırakabilir. Kullanıcı yedeklemeyi devre dışı bıraktığında Android Backup Service, kaydedilen tüm yedekleme verilerini siler. Kullanıcı, cihazda yedeklemeyi yeniden etkinleştirebilir ancak Android Backup Service, daha önce silinen verileri geri yüklemez.