Android Backup Service (سرویس پشتیبانگیری Android) پشتیبانگیری و بازیابی فضای ذخیرهسازی ابری را برای دادههای کلید-مقدار در برنامه Android شما ارائه میدهد. درطول عملیات پشتیبانگیری کلید-مقدار، دادههای پشتیبانگیری برنامه به انتقال پشتیبانگیری دستگاه منتقل میشود. اگر دستگاه از انتقال پشتیبانی Google پیشفرض استفاده میکند، دادهها برای بایگانی شدن به Android Backup Service ارسال میشود.
دادهها به ۵ مگابایت برای هر کاربر برنامهتان محدود است. برای ذخیره کردن دادههای پشتیبانگیریشده هزینهای دریافت نمیشود.
برای دریافت نمای کلی از گزینههای پشتیبانگیری Android و راهنمایی درباره اینکه کدام دادهها را باید پشتیبانگیری و بازیابی کنید، به نمای کلی پشتیبانگیری داده مراجعه کنید.
پیادهسازی پشتیبانگیری کلید-مقدار
برای پشتیبانگیری از دادههای برنامهتان، باید عامل پشتیبانگیری را پیادهسازی کنید. «مدیر پشتیبانگیری» هم درطول پشتیبانگیری و هم درطول بازیابی، عامل پشتیبانگیری شما را فراخوانی میکند.
برای پیادهسازی عامل پشتیبانگیری، باید:
عامل پشتیبانگیری را در فایل مانیفست با مشخصه
android:backupAgentاعلام کنید.با انجام یکی از کارهای زیر، عامل پشتیبانگیری را تعریف کنید:
-
کلاس
BackupAgentمیانای مرکزی را ارائه میدهد که برنامهتان برای برقراری ارتباط با «مدیر پشتیبانگیری» از آن استفاده میکند. اگر این کلاس را مستقیماً گسترش دهید، بایدonBackup()وonRestore()را لغو کنید تا عملیات پشتیبانگیری و بازیابی دادههایتان را مدیریت کنید. درحال گسترش دادن
BackupAgentHelperکلاس
BackupAgentHelperیک پوشاننده مناسب برای کلاسBackupAgentارائه میدهد، و مقدار کدی را که باید بنویسید به حداقل میرساند. درBackupAgentHelper، باید از یک یا چند شیء کمکی استفاده کنید که بهطور خودکار انواع خاصی از دادهها را پشتیبانگیری و بازیابی میکنند تا نیازی به پیادهسازیonBackup()وonRestore()نداشته باشید. توصیه میکنیم برای مدیریت پشتیبانگیریهای برنامهتان ازBackupAgentHelperاستفاده کنید، مگر اینکه به کنترل کامل بر پشتیبانگیریهای برنامهتان نیاز داشته باشید.درحالحاضر Android دستیارهای پشتیبانگیریای ارائه میدهد که فایلهای کامل را از
SharedPreferencesو فضای ذخیرهسازی داخلی پشتیبانگیری و بازیابی میکنند.
-
اعلام کردن عامل پشتیبانگیری در مانیفست
وقتی درباره نام کلاس برای عامل پشتیبانگیریتان تصمیم گرفتید، آن را در مانیفست خود بااستفاده از ویژگی android:backupAgent در برچسب <application> اعلام کنید.
برای مثال:
<manifest ... > ... <application android:label="MyApplication" android:backupAgent="MyBackupAgent"> <meta-data android:name="com.google.android.backup.api_key" android:value="unused" /> <activity ... > ... </activity> </application> </manifest>
برای پشتیبانی از دستگاههای قدیمیتر، توصیه میکنیم کلید میانای برنامهسازی کاربردی <meta-data>
را به فایل مانیفست Android خود اضافه کنید. «سرویس پشتیبانگیری Android» دیگر به کلید سرویس نیاز ندارد، اما برخیاز دستگاههای قدیمیتر ممکن است همچنان هنگام پشتیبانگیری کلید را بررسی کنند. android:name را روی com.google.android.backup.api_key و
android:value را روی unused تنظیم کنید.
مشخصه
android:restoreAnyVersion
مقدار بولی میگیرد تا نشان دهد آیا میخواهید دادههای برنامه را بدون درنظر گرفتن نسخه فعلی برنامه درمقایسه با نسخهای که دادههای پشتیبان را تولید کرده است بازیابی کنید یا نه. مقدار پیشفرض false است. برای اطلاعات بیشتر، به بررسی نسخه دادههای بازیابی مراجعه کنید.
گسترش BackupAgentHelper
اگر میخواهید فایلهای کامل را از SharedPreferences یا حافظه داخلی پشتیبانگیری کنید، باید عامل پشتیبانگیریتان را بااستفاده از BackupAgentHelper بسازید.
ساختن عامل پشتیبانگیری با BackupAgentHelper به کد بسیار کمتری نسبت به
گسترش BackupAgent نیاز دارد، زیرا لازم نیست onBackup() و
onRestore() را پیادهسازی کنید.
پیادهسازی BackupAgentHelper شما باید از یک یا چند کمککننده پشتیبانگیری استفاده کند.
کمککننده پشتیبانگیری مؤلفهای تخصصی است که BackupAgentHelper برای انجام عملیات پشتیبانگیری و بازیابی برای نوع خاصی از دادهها فراخوانی میکند. درحالحاضر چارچوب Android دو کمککننده مختلف ارائه میدهد:
SharedPreferencesBackupHelperبرای پشتیبانگیری ازSharedPreferencesفایل.FileBackupHelperبرای پشتیبانگیری از فایلهای حافظه داخلی.
میتوانید چند کمککننده در BackupAgentHelper خود اضافه کنید، اما فقط یک کمککننده برای هر نوع داده لازم است. یعنی اگر چند فایل
SharedPreferences دارید، فقط به یک
SharedPreferencesBackupHelper نیاز دارید.
برای هر کمککنندهای که میخواهید به BackupAgentHelper اضافه کنید، باید
درطول روش
onCreate()
کارهای زیر را انجام دهید:
- نمونهای از کلاس کمکی موردنظر را نمونهسازی کنید. در سازنده کلاس، باید فایل(های) موردنظرتان را برای پشتیبانگیری مشخص کنید.
- با
addHelper()تماس بگیرید تا کمکرسان را بهBackupAgentHelperخود اضافه کنید.
بخشهای زیر نحوه ایجاد عامل پشتیبانگیری را بااستفاده از هریک از کمککنندههای دردسترس شرح میدهد.
پشتیبانگیری از SharedPreferences
وقتی SharedPreferencesBackupHelper را نمونهسازی میکنید، باید نام یک یا چند فایل SharedPreferences را اضافه کنید.
برای مثال، برای پشتیبانگیری از فایل SharedPreferences با نام user_preferences،
یک عامل پشتیبانگیری کامل بااستفاده از BackupAgentHelper بهصورت زیر است:
کاتلین
// 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) } } }
جاوا
public class MyPrefsBackupAgent extends BackupAgentHelper { // The name of the SharedPreferences file static final String PREFS = "user_preferences"; // A key to uniquely identify the set of backup data static final String PREFS_BACKUP_KEY = "prefs"; // Allocate a helper and add it to the backup agent @Override public void onCreate() { SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS); addHelper(PREFS_BACKUP_KEY, helper); } }
SharedPreferencesBackupHelper شامل همه کدهای لازم برای پشتیبانگیری و
بازیابی فایل SharedPreferences است.
وقتی «مدیر پشتیبانگیری» onBackup() و onRestore() را فراخوانی میکند،
BackupAgentHelper دستیاران پشتیبانگیری شما را فراخوانی میکند تا از فایلهای مشخصشده شما
پشتیبانگیری و آنها را بازیابی کند.
پشتیبانگیری از فایلهای دیگر
وقتی FileBackupHelper را نمونهسازی میکنید، باید نام یک یا چند فایل را که در فضای ذخیرهسازی داخلی برنامهتان ذخیره شدهاند، همانطور که توسط getFilesDir() مشخص شده است، اضافه کنید. این همان مکانی است که openFileOutput() فایلها را مینویسد.
برای مثال، برای پشتیبانگیری از دو فایل بهنام scores و stats، عامل پشتیبانگیری
بااستفاده از BackupAgentHelper بهاینصورت است:
کاتلین
// 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) } } }
جاوا
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 شامل همه کدهای لازم برای پشتیبانگیری و بازیابی
فایلهایی است که در فضای ذخیرهسازی داخلی برنامهتان ذخیره شدهاند.
بااینحال، خواندن و نوشتن در فایلهای حافظه داخلی ایمن از رشته نیست. برای اطمینان از اینکه عامل پشتیبانگیری شما فایلهایتان را همزمان با فعالیتهایتان نمیخواند یا نمینویسد، باید هربار که خواندن یا نوشتن انجام میدهید از عبارتهای همگامسازیشده استفاده کنید. برای مثال، در هر فعالیتی که فایل را میخوانید و مینویسید، به شیئی نیاز دارید که بهعنوان قفل ذاتی برای دستورات همگامسازیشده استفاده شود:
کاتلین
// Object for intrinsic lock companion object { val sDataLock = Any() }
جاوا
// Object for intrinsic lock static final Object sDataLock = new Object();
سپس هربار که فایلها را میخوانید یا مینویسید، با این قفل یک عبارت همگامسازیشده ایجاد کنید. برای مثال، در اینجا یک عبارت همگامسازیشده برای نوشتن آخرین امتیاز در یک بازی در یک فایل آورده شده است:
کاتلین
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") }
جاوا
try { synchronized (MyActivity.sDataLock) { File dataFile = new File(getFilesDir(), TOP_SCORES); RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw"); raFile.writeInt(score); } } catch (IOException e) { Log.e(TAG, "Unable to write to file"); }
باید عبارتهای خواندهشده را با همان قفل همگامسازی کنید.
سپس، در BackupAgentHelper، باید onBackup() و onRestore() را لغو کنید تا عملیات پشتیبانگیری و بازیابی با همان قفل ذاتی همگامسازی شود. برای مثال، نمونه MyFileBackupAgent از بالا به
روشهای زیر نیاز دارد:
کاتلین
@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) } }
جاوا
@Override public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException { // Hold the lock while the FileBackupHelper performs back up synchronized (MyActivity.sDataLock) { super.onBackup(oldState, data, newState); } } @Override public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { // Hold the lock while the FileBackupHelper restores the file synchronized (MyActivity.sDataLock) { super.onRestore(data, appVersionCode, newState); } }
گسترش BackupAgent
اکثر برنامهها نباید مستقیماً کلاس BackupAgent را گسترش دهند، بلکه باید
BackupAgentHelper را گسترش دهند تا از
کلاسهای کمکی داخلی که بهطور خودکار از فایلهای شما پشتیبانگیری و بازیابی میکنند، بهرهمند شوند.
اما ممکن است BackupAgent را مستقیماً برای انجام کارهای زیر گسترش دهید:
- قالب دادههایتان را نسخهبندی کنید. برای مثال، اگر پیشبینی میکنید که لازم است قالب نوشتن دادههای برنامهتان را اصلاح کنید، میتوانید یک عامل پشتیبانگیری بسازید تا نسخه برنامهتان را درطول عملیات بازیابی بررسی کند و اگر نسخه موجود در دستگاه با نسخه دادههای پشتیبانگیری متفاوت بود، هرگونه کار سازگاری لازم را انجام دهد. برای اطلاعات بیشتر، به بررسی نسخه دادههای بازیابی مراجعه کنید.
- بخشهایی از دادهها را برای پشتیبانگیری مشخص کنید. بهجای پشتیبانگیری از کل فایل، میتوانید بخشهایی از دادهها را برای پشتیبانگیری مشخص کنید و سپس نحوه بازیابی هر بخش در دستگاه را تعیین کنید. این کار همچنین میتواند به شما کمک کند نسخههای مختلف را مدیریت کنید، زیرا دادههایتان را بهجای فایلهای کامل، بهعنوان موجودیتهای منحصربهفرد میخوانید و مینویسید.
- پشتیبانگیری از دادهها در پایگاه داده. اگر پایگاه داده SQLite دارید که میخواهید
وقتی کاربر برنامهتان را دوباره نصب میکند آن را بازیابی کنید، باید
BackupAgentسفارشی بسازید که دادههای مناسب را درطول عملیات پشتیبانگیری بخواند، سپس جدولتان را ایجاد کنید و دادهها را درطول عملیات بازیابی درج کنید.
اگر نیازی به انجام هیچیک از کارهای بالا ندارید و میخواهید از فایلهای کامل در SharedPreferences یا حافظه داخلی پشتیبانگیری کنید، به گسترش دادن BackupAgentHelper مراجعه کنید.
روشهای الزامی
وقتی BackupAgent ایجاد میکنید، باید روشهای فراخوانی زیر را پیادهسازی کنید:
onBackup()- «مدیر پشتیبانگیری» این روش را پساز اینکه درخواست پشتیبانگیری کردید فراخوانی میکند. در این روش، دادههای برنامهتان را از دستگاه میخوانید و دادههایی را که میخواهید پشتیبانگیری شود به «مدیر پشتیبانگیری» ارسال میکنید، همانطور که در انجام پشتیبانگیری شرح داده شده است.
onRestore()«مدیر پشتیبانگیری» این روش را درطول عملیات بازیابی فراخوانی میکند. این روش دادههای پشتیبانگیریشده را ارائه میدهد که برنامهتان میتواند از آن برای بازیابی وضعیت قبلی خود استفاده کند، همانطور که در انجام بازیابی شرح داده شده است.
وقتی کاربر برنامهتان را دوباره نصب میکند، سیستم این روش را برای بازیابی دادههای پشتیبانگیریشده فراخوانی میکند، اما برنامهتان هم میتواند درخواست بازیابی کند.
پشتیبانگیری
درخواست پشتیبانگیری منجر به تماس فوری با روش onBackup() شما نمیشود. درعوض، «مدیر پشتیبانگیری» منتظر زمان مناسب میماند، سپس
برای همه برنامههایی که از زمان آخرین پشتیبانگیری درخواست پشتیبانگیری کردهاند،
پشتیبانگیری انجام میدهد. این نقطهای است که باید دادههای برنامهتان را به «مدیر پشتیبانگیری» ارائه دهید تا بتواند آن را در فضای ذخیرهسازی ابری ذخیره کند.
فقط «مدیر پشتیبانگیری» میتواند روش onBackup() عامل پشتیبانگیری شما را فراخوانی کند. هرزمان که دادههای برنامهتان تغییر میکند و میخواهید پشتیبانگیری انجام دهید، باید با فراخوانی dataChanged() درخواست عملیات پشتیبانگیری کنید.
برای اطلاعات بیشتر، به درخواست پشتیبانگیری مراجعه کنید.
نکته: هنگام توسعه برنامهتان، میتوانید بااستفاده از ابزار bmgr، عملیات پشتیبانگیری فوری را از «مدیر پشتیبانگیری» آغاز کنید.
وقتی «مدیر پشتیبانگیری» روش onBackup() شما را فراخوانی میکند، سه پارامتر را ارسال میکند:
oldState- یک
ParcelFileDescriptorباز و فقط خواندنی که به آخرین وضعیت پشتیبانگیری ارائهشده توسط برنامه شما اشاره میکند. این دادههای پشتیبانگیریشده از فضای ذخیرهسازی ابری نیست، بلکه نمایشی محلی از دادههایی است که آخرینبار هنگام فراخوانیonBackup()پشتیبانگیری شدهاند، همانطور که توسطnewStateیا ازonRestore()تعریف شده است.onRestore()در بخش بعدی پوشش داده شده است. BecauseonBackup()does not allow you to read existing backup data in the cloud storage, you can use this local representation to determine whether your data has changed since the last backup. data- یک شیء
BackupDataOutputکه از آن برای ارسال دادههای پشتیبانگیری به «مدیر پشتیبانگیری» استفاده میکنید. newState- یک
ParcelFileDescriptorباز، خواندن/نوشتن که به فایلی اشاره میکند که در آن باید نمایشی از دادههایی را که بهdataتحویل دادهاید بنویسید. نمایش میتواند بهسادگی مُهر زمان آخرین اصلاح فایل شما باشد. دفعه بعدی که «مدیر پشتیبانگیری» روشonBackup()شما را فراخوانی میکند، این شیء بهعنوانoldStateبرگردانده میشود. اگر دادههای پشتیبانگیری را درnewStateننویسید، دفعه بعد که «مدیر پشتیبانگیری»onBackup()را فراخوانی میکند،oldStateبه فایل خالی اشاره خواهد کرد.
بااستفاده از این پارامترها، روش onBackup() خود را برای انجام کارهای زیر پیادهسازی کنید:
با مقایسه کردن
oldStateبا دادههای فعلیتان، بررسی کنید که آیا دادههایتان از آخرین پشتیبانگیری تغییر کرده است یا نه. نحوه خواندن دادهها درoldStateبه نحوه نوشتن اولیه آن درnewStateبستگی دارد (مرحله ۳ را ببینید). آسانترین راه برای ثبت وضعیت فایل، استفاده از مُهر زمان آخرین اصلاح آن است. برای مثال، در اینجا نحوه خواندن و مقایسه مُهر زمان ازoldStateآورده شده است:کاتلین
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 }
جاوا
// 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 }
اگر چیزی تغییر نکرده است و نیازی به پشتیبانگیری ندارید، به مرحله ۳ بروید.
اگر دادههایتان درمقایسه با
oldStateتغییر کرده است، دادههای فعلی را درdataبنویسید تا در فضای ذخیرهسازی ابری پشتیبانگیری شود.باید هر بخش از دادهها را بهعنوان یک نهاد در
BackupDataOutputبنویسید. نهاد یک سابقه داده دودویی مسطح است که با رشته کلید یکتایی شناسایی میشود. بنابراین، مجموعه دادهای که پشتیبانگیری میکنید ازنظر مفهومی مجموعهای از جفتهای کلید-مقدار است.برای افزودن نهاد به مجموعه دادههای پشتیبانگیری، باید:
writeEntityHeader()را فراخوانی کنید و کلید رشتهای یکتایی را برای دادههایی که میخواهید بنویسید و اندازه دادهها ارسال کنید.writeEntityData()را فراخوانی کنید و میانگیر بایتی را که حاوی دادههای شما است و تعداد بایتهایی را که باید از میانگیر نوشته شود (که باید با اندازه ارسالشده بهwriteEntityHeader()مطابقت داشته باشد) ارسال کنید.
برای مثال، کد زیر برخیاز دادهها را به یک جریان بایت تبدیل میکند و آن را در یک نهاد واحد مینویسد:
کاتلین
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) }
جاوا
// 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);
این کار را برای هر دادهای که میخواهید پشتیبانگیری شود انجام دهید. نحوه تقسیم کردن دادهها به نهادها به شما بستگی دارد. حتی ممکن است فقط از یک نهاد استفاده کنید.
چه پشتیبانگیری را انجام دهید (در مرحله ۲) چه انجام ندهید، نمایشی از دادههای فعلی را در
newStateParcelFileDescriptorبنویسید. «مدیر پشتیبانگیری» این شیء را بهصورت محلی بهعنوان نمایشی از دادههایی که درحالحاضر پشتیبانگیری شدهاند حفظ میکند. دفعه بعد کهonBackup()را فراخوانی میکند، این مقدار را بهعنوانoldStateبه شما برمیگرداند تا بتوانید تعیین کنید که آیا پشتیبانگیری دیگری لازم است یا نه، همانطور که در مرحله ۱ انجام شد. اگر وضعیت دادههای فعلی را در این فایل ننویسید،oldStateدرطول فراخوانی بعدی خالی خواهد بود.مثال زیر نمایشی از دادههای فعلی را بااستفاده از مُهر زمان آخرین تغییر فایل در
newStateذخیره میکند:کاتلین
val modified = dataFile.lastModified() FileOutputStream(newState.fileDescriptor).also { DataOutputStream(it).apply { writeLong(modified) } }
جاوا
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); long modified = dataFile.lastModified(); out.writeLong(modified);
انجام بازیابی
وقتی زمان بازیابی دادههای برنامه شما فرامیرسد، «مدیر پشتیبانگیری» روش onRestore() عامل پشتیبانگیری شما را فراخوانی میکند. وقتی این روش را فراخوانی میکند، «مدیر پشتیبانگیری»
دادههای پشتیبانگیریشده را ارائه میدهد تا بتوانید آن را در دستگاه بازیابی کنید.
فقط «مدیر پشتیبانگیری» میتواند onRestore() را فراخوانی کند، که این کار بهطور خودکار
هنگام نصب برنامه شما توسط سیستم و پیدا کردن دادههای پشتیبانگیری موجود انجام میشود.
وقتی «مدیر پشتیبانگیری» روش onRestore() شما را فراخوانی میکند، سه پارامتر را ارسال میکند:
data- شیء
BackupDataInput، که به شما امکان میدهد دادههای پشتیبانگیریشده را بخوانید. appVersionCode- عدد صحیحی که نشاندهنده مقدار مشخصه مانیفست
android:versionCodeبرنامهتان است، همانطور که هنگام پشتیبانگیری از این دادهها بود. میتوانید از این برای بررسی نسخه فعلی برنامه و تعیین اینکه آیا قالب داده سازگار است یا نه استفاده کنید. برای اطلاعات بیشتر درباره استفاده از این روش برای مدیریت نسخههای مختلف دادههای بازیابی، به بررسی نسخه دادههای بازیابی مراجعه کنید. newState- یک
ParcelFileDescriptorباز، خواندن/نوشتن که به فایلی اشاره میکند که در آن باید وضعیت پشتیبانگیری نهایی را که باdataارائه شده است بنویسید. این شیء دفعه بعد کهonBackup()فراخوانی شود، بهصورتoldStateبرگردانده میشود. بهیاد داشته باشید که باید همان شیءnewStateرا در callbackonBackup()بنویسید—انجام این کار در اینجا همچنین تضمین میکند که شیءoldStateدادهشده بهonBackup()معتبر است، حتی اولین باری کهonBackup()پساز بازیابی دستگاه فراخوانی میشود.
در پیادهسازی onRestore()، باید
readNextHeader()
را در data فراخوانی کنید تا همه نهادها در مجموعه داده تکرار شوند. برای هر نهاد
پیداشده، کارهای زیر را انجام دهید:
- دریافت کلید نهاد با
getKey(). کلید نهاد را با فهرستی از مقادیر کلید شناختهشده که باید بهعنوان رشتههای نهایی ثابت در کلاس
BackupAgentخود اعلام کرده باشید، مقایسه کنید. وقتی کلید با یکیاز رشتههای کلید شناختهشده شما مطابقت دارد، وارد عبارتی شوید تا دادههای نهاد را استخراج کنید و آن را در دستگاه ذخیره کنید:- اندازه دادههای موجودیت را با
getDataSize()دریافت کنید و آرایه بایتی با آن اندازه ایجاد کنید. readEntityData()را فراخوانی کنید و آرایه بایت را به آن ارسال کنید، که محل قرارگیری دادهها است، و انحراف شروع و اندازه خواندن را مشخص کنید.- آرایه بایت شما اکنون پر است. دادهها را بخوانید و هرطور که دوست دارید آنها را در دستگاه بنویسید.
- اندازه دادههای موجودیت را با
پساز خواندن و نوشتن دادههایتان در دستگاه، وضعیت دادههایتان را در پارامتر
newStateبنویسید، همانطور که درطولonBackup()انجام میدهید.
برای مثال، در اینجا نحوه بازیابی دادههای پشتیبانگیریشده توسط مثال در بخش قبلی آورده شده است:
کاتلین
@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) } } }
جاوا
@Override public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException { // There should be only one entity, but the safest // way to consume it is using a while loop while (data.readNextHeader()) { String key = data.getKey(); int dataSize = data.getDataSize(); // If the key is ours (for saving top score). Note this key was used when // we wrote the backup entity header if (TOPSCORE_BACKUP_KEY.equals(key)) { // Create an input stream for the BackupDataInput byte[] dataBuf = new byte[dataSize]; data.readEntityData(dataBuf, 0, dataSize); ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf); DataInputStream in = new DataInputStream(baStream); // Read the player name and score from the backup data playerName = in.readUTF(); playerScore = in.readInt(); // Record the score on the device (to a file or something) recordScore(playerName, playerScore); } else { // We don't know this entity key. Skip it. (Shouldn't happen.) data.skipEntityData(); } } // Finally, write to the state blob (newState) that describes the restored data FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); out.writeUTF(playerName); out.writeInt(mPlayerScore); }
در این مثال، از پارامتر appVersionCode که به onRestore() ارسال شده است استفاده نمیشود. بااینحال، اگر انتخاب کرده باشید که وقتی نسخه برنامه کاربر درواقع به عقب برگشته است (برای مثال، کاربر از نسخه ۱.۵ برنامه شما به نسخه ۱.۰ رفته است) پشتیبانگیری انجام شود، ممکن است بخواهید از آن استفاده کنید. برای اطلاعات بیشتر،
بخش بعدی را ببینید.
بررسی نسخه دادههای بازیابی
وقتی «مدیر پشتیبانگیری» دادههایتان را در فضای ذخیرهسازی ابری ذخیره میکند، بهطور خودکار
نسخه برنامهتان را که توسط مشخصه android:versionCode فایل مانیفست شما تعریف شده است
دربرمیگیرد. قبلاز اینکه «مدیر پشتیبانگیری» برای بازیابی دادههایتان با عامل پشتیبانگیری تماس بگیرد، android:versionCode برنامه نصبشده را بررسی میکند و آن را با مقدار ثبتشده در مجموعه دادههای بازیابی مقایسه میکند. اگر
نسخه ثبتشده در مجموعه دادههای بازیابی جدیدتر از نسخه برنامه در
دستگاه باشد، کاربر برنامهاش را تنزل داده است. در این حالت، «مدیر
پشتیبانگیری» عملیات بازیابی را برای برنامهتان لغو میکند و روش
onRestore() شما را فراخوانی نمیکند، زیرا مجموعه بازیابی برای نسخه قدیمیتر
بیمعنی تلقی میشود.
میتوانید این رفتار را با مشخصه android:restoreAnyVersion لغو کنید.
این مشخصه را روی true تنظیم کنید تا نشان دهید که میخواهید برنامه را
صرفنظر از نسخه مجموعه بازیابی، بازیابی کنید. مقدار پیشفرض false است. اگر این را روی true تنظیم کنید، «مدیر پشتیبانگیری» android:versionCode را نادیده میگیرد و در همه موارد روش onRestore() شما را فراخوانی میکند. با انجام این کار، میتوانید بهصورت دستی تفاوت نسخه را در روش onRestore() خود بررسی کنید و درصورت عدم تطابق نسخهها، اقدامات لازم را برای سازگار کردن دادهها انجام دهید.
برای کمک به شما در مدیریت نسخههای مختلف درطول عملیات بازیابی،
روش onRestore() کد نسخه موجود در مجموعه دادههای بازیابی را
بهعنوان پارامتر appVersionCode به شما منتقل میکند. سپس میتوانید کد نسخه برنامه فعلی را با فیلد
PackageInfo.versionCode
پرسوجو کنید. برای مثال:
کاتلین
val info: PackageInfo? = try { packageManager.getPackageInfo(packageName, 0) } catch (e: PackageManager.NameNotFoundException) { null } val version: Int = info?.versionCode ?: 0
جاوا
PackageInfo info; try { String name = getPackageName(); info = getPackageManager().getPackageInfo(name, 0); } catch (NameNotFoundException nnfe) { info = null; } int version; if (info != null) { version = info.versionCode; }
سپس version بهدستآمده از
PackageInfo را با
appVersionCode منتقلشده به onRestore() مقایسه کنید.
درخواست نسخه پشتیبان
هرزمان بخواهید میتوانید با فراخوانی dataChanged()، عملیات پشتیبانگیری را درخواست کنید. این
روش به «مدیر پشتیبانگیری» اطلاع میدهد که میخواهید از دادههایتان بااستفاده از
عامل پشتیبانگیریتان پشتیبانگیری کنید. سپس «مدیر پشتیبانگیری» روش onBackup() عامل پشتیبانگیری شما را در زمانی در آینده فراخوانی میکند. معمولاً باید هربار که دادههایتان تغییر میکند (مثلاً وقتی کاربر اولویت برنامهای را که میخواهید پشتیبانگیری کنید تغییر میدهد) درخواست پشتیبانگیری کنید. اگر قبلاز اینکه «مدیر پشتیبانگیری» از نماینده شما درخواست پشتیبانگیری کند، چندینبار با dataChanged() تماس بگیرید، نماینده شما همچنان فقط یک تماس با onBackup() دریافت میکند.
درخواست بازیابی
درطول عمر عادی برنامهتان، نباید نیازی به درخواست عملیات بازیابی داشته باشید. سیستم بهطور خودکار دادههای پشتیبان را بررسی میکند و هنگام نصب برنامهتان، بازیابی را انجام میدهد.
انتقال به «پشتیبانگیری خودکار»
میتوانید با تنظیم کردن
android:fullBackupOnly
روی true در عنصر <application> در فایل مانیفست، برنامهتان را به پشتیبانگیری کامل دادهها انتقال دهید. هنگام اجرا
در دستگاهی با Android نسخه ۵.۱ (سطح میانای برنامهسازی کاربردی ۲۲) یا پایینتر، برنامهتان این
مقدار را در مانیفست نادیده میگیرد و به پشتیبانگیری کلید-مقدار ادامه میدهد. وقتی برنامه در دستگاهی با Android نسخه ۶.۰ (سطح میانای برنامهسازی کاربردی ۲۳) یا بالاتر اجرا میشود، بهجای پشتیبانگیری مقدار کلید، «پشتیبانگیری خودکار» انجام میدهد.
حریم خصوصی کاربران
ما در Google کاملاً از اعتمادی که کاربران به ما دارند و مسئولیتمان برای محافظت از حریم خصوصی کاربران آگاه هستیم. Google دادههای پشتیبانگیری را بهطور ایمن به سرورهای Google ارسال و از آنها دریافت میکند تا ویژگیهای پشتیبانگیری و بازیابی را ارائه دهد. Google مانند اطلاعات شخصی با این دادهها برخورد میکند و این کار را مطابق با خطمشی رازداری Google انجام میدهد.
علاوهبراین، کاربران میتوانند عملکرد پشتیبانگیری داده را ازطریق تنظیمات پشتیبانگیری سیستم Android غیرفعال کنند. وقتی کاربر پشتیبانگیری را غیرفعال میکند، «سرویس پشتیبانگیری Android» همه دادههای پشتیبانگیری ذخیرهشده را حذف میکند. کاربر میتواند پشتیبانگیری را دوباره در دستگاه فعال کند، اما «سرویس پشتیبانگیری Android» هیچکدام از دادههای قبلاً حذفشده را بازیابی نخواهد کرد.