Android Backup Service มีบริการสำรองและกู้คืนข้อมูลในพื้นที่เก็บข้อมูลระบบคลาวด์สำหรับข้อมูลคีย์-ค่าในแอป Android ของคุณ ในระหว่างการสำรองข้อมูลคีย์-ค่า ระบบจะส่งข้อมูลสำรองของแอปไปยังการส่งข้อมูลสำรองของอุปกรณ์ หากอุปกรณ์ใช้ Google ถ่ายโอนข้อมูลสำรองเริ่มต้น ระบบจะส่งข้อมูลไปยัง Android Backup Service เพื่อเก็บถาวร
ข้อมูลจะจำกัดอยู่ที่ 5 MB ต่อผู้ใช้แอปของคุณ และไม่มีค่าใช้จ่ายในการจัดเก็บข้อมูลสำรอง
ดูภาพรวมของตัวเลือกการสำรองข้อมูลของ Android และคำแนะนำเกี่ยวกับข้อมูลที่คุณควรสำรองและกู้คืนได้ที่ภาพรวมการสำรองข้อมูล
ใช้การสำรองข้อมูลคีย์-ค่า
หากต้องการสำรองข้อมูลแอป คุณต้องติดตั้งใช้งานตัวแทนการสำรองข้อมูล ตัวแทนการสำรองข้อมูลจะถูกเรียกโดย Backup Manager ทั้งในระหว่างการสำรองข้อมูลและการกู้คืน
หากต้องการใช้ Agent สำรอง คุณต้องดำเนินการต่อไปนี้
ประกาศตัวแทนการสำรองข้อมูลในไฟล์ Manifest ด้วยแอตทริบิวต์
android:backupAgentกำหนดตัวแทนสำรองโดยทำอย่างใดอย่างหนึ่งต่อไปนี้
-
คลาส
BackupAgentมีอินเทอร์เฟซส่วนกลางที่แอปใช้เพื่อสื่อสารกับเครื่องมือจัดการการสำรองข้อมูล หากคุณขยายคลาสนี้โดยตรง คุณต้องลบล้างonBackup()และonRestore()เพื่อจัดการการดำเนินการสำรองและกู้คืนข้อมูล -
คลาส
BackupAgentHelperมี Wrapper ที่สะดวกสำหรับคลาสBackupAgentซึ่งช่วยลดจำนวนโค้ดที่คุณต้องเขียน ในBackupAgentHelperคุณต้องใช้ออบเจ็กต์ตัวช่วยอย่างน้อย 1 รายการ ซึ่งจะสำรองและกู้คืนข้อมูลบางประเภทโดยอัตโนมัติ เพื่อให้คุณไม่ต้องใช้onBackup()และonRestore()เราขอแนะนำให้ใช้BackupAgentHelperเพื่อจัดการการสำรองข้อมูลของแอป เว้นแต่คุณต้องการควบคุมการสำรองข้อมูลของแอปอย่างเต็มรูปแบบปัจจุบัน Android มีตัวช่วยสำรองข้อมูลที่จะสำรองและกู้คืนไฟล์ทั้งหมดจาก
SharedPreferencesและที่จัดเก็บข้อมูลภายใน
-
ประกาศตัวแทนการสำรองข้อมูลในไฟล์ Manifest
เมื่อเลือกชื่อคลาสสำหรับตัวแทนการสำรองข้อมูลแล้ว ให้ประกาศชื่อนั้นในไฟล์ Manifest โดยใช้แอตทริบิวต์ android:backupAgent ในแท็ก <application>
เช่น
<manifest ... >
...
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
<meta-data android:name="com.google.android.backup.api_key"
android:value="unused" />
<activity ... >
...
</activity>
</application>
</manifest>
หากต้องการรองรับอุปกรณ์รุ่นเก่า เราขอแนะนำให้เพิ่มคีย์ API <meta-data> ลงในไฟล์ Manifest ของ Android Android Backup Service ไม่จำเป็นต้องใช้คีย์บริการอีกต่อไป แต่อุปกรณ์รุ่นเก่าบางรุ่นอาจยังคงตรวจสอบคีย์เมื่อสำรองข้อมูล ตั้งค่า android:name เป็น com.google.android.backup.api_key และตั้งค่า android:value เป็น unused
แอตทริบิวต์ android:restoreAnyVersion จะใช้ค่าบูลีนเพื่อระบุว่าคุณต้องการกู้คืนข้อมูลแอปหรือไม่ โดยไม่คำนึงถึงเวอร์ชันปัจจุบันของแอปเมื่อเทียบกับเวอร์ชันที่สร้างข้อมูลสำรอง ค่าเริ่มต้นคือ false ดูข้อมูลเพิ่มเติมได้ที่หัวข้อตรวจสอบเวอร์ชันของข้อมูลที่กู้คืน
ขยาย BackupAgentHelper
คุณควรสร้างตัวแทนการสำรองข้อมูลโดยใช้ BackupAgentHelper หากต้องการสำรองไฟล์ทั้งหมดจาก SharedPreferences หรือที่จัดเก็บข้อมูลภายใน
การสร้างตัวแทนสำรองข้อมูลด้วย BackupAgentHelper ใช้โค้ดน้อยกว่าการขยาย BackupAgent มาก เนื่องจากคุณไม่จำเป็นต้องใช้ onBackup() และ onRestore()
การติดตั้งใช้งาน BackupAgentHelper ต้องใช้ตัวช่วยสำรองอย่างน้อย 1 รายการ
ตัวช่วยสำรองข้อมูลเป็นคอมโพเนนต์เฉพาะที่ BackupAgentHelper เรียกใช้เพื่อดำเนินการสำรองและกู้คืนข้อมูลบางประเภท ปัจจุบันเฟรมเวิร์ก Android มีตัวช่วย 2 แบบ ได้แก่
SharedPreferencesBackupHelperเพื่อสำรองข้อมูลไฟล์SharedPreferencesรายการFileBackupHelperเพื่อสำรองไฟล์จากที่จัดเก็บข้อมูลภายใน
คุณสามารถรวมผู้ช่วยหลายคนไว้ใน BackupAgentHelper ได้ แต่จำเป็นต้องมีผู้ช่วยเพียงคนเดียวสำหรับข้อมูลแต่ละประเภท กล่าวคือ หากคุณมีไฟล์ SharedPreferences หลายไฟล์ คุณก็ต้องมี SharedPreferencesBackupHelper เพียงไฟล์เดียว
สำหรับผู้ช่วยแต่ละคนที่ต้องการเพิ่มลงใน BackupAgentHelper คุณต้องทำดังต่อไปนี้ในระหว่างเมธอด onCreate()
- สร้างอินสแตนซ์ของคลาสตัวช่วยที่เลือก ในตัวสร้างคลาส คุณต้องระบุไฟล์ที่ต้องการสำรองข้อมูล
- โทรหา
addHelper()เพื่อเพิ่มผู้ช่วยลงในBackupAgentHelper
ส่วนต่อไปนี้จะอธิบายวิธีสร้างตัวแทนสำรองโดยใช้ตัวช่วยแต่ละรายการที่มีอยู่
สำรองข้อมูล SharedPreferences
เมื่อสร้างอินสแตนซ์ SharedPreferencesBackupHelper คุณต้องระบุชื่อไฟล์ SharedPreferences อย่างน้อย 1 ไฟล์
ตัวอย่างเช่น หากต้องการสำรองข้อมูลไฟล์ SharedPreferences ชื่อ user_preferences ตัวแทนการสำรองข้อมูลที่สมบูรณ์ซึ่งใช้ BackupAgentHelper จะมีลักษณะดังนี้
Kotlin
// The name of the SharedPreferences file
const val PREFS = "user_preferences"
// A key to uniquely identify the set of backup data
const val PREFS_BACKUP_KEY = "prefs"
class MyPrefsBackupAgent : BackupAgentHelper() {
override fun onCreate() {
// Allocate a helper and add it to the backup agent
SharedPreferencesBackupHelper(this, PREFS).also {
addHelper(PREFS_BACKUP_KEY, it)
}
}
}
Java
public class MyPrefsBackupAgent extends BackupAgentHelper {
// The name of the SharedPreferences file
static final String PREFS = "user_preferences";
// A key to uniquely identify the set of backup data
static final String PREFS_BACKUP_KEY = "prefs";
// Allocate a helper and add it to the backup agent
@Override
public void onCreate() {
SharedPreferencesBackupHelper helper =
new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
}
SharedPreferencesBackupHelper มีโค้ดทั้งหมดที่จำเป็นในการสำรองข้อมูลและกู้คืนไฟล์ SharedPreferences
เมื่อตัวจัดการการสำรองข้อมูลเรียกใช้ onBackup() และ onRestore()
BackupAgentHelper จะเรียกใช้ตัวช่วยสำรองข้อมูลเพื่อสำรองและกู้คืนไฟล์ที่คุณระบุ
สำรองข้อมูลไฟล์อื่นๆ
เมื่อสร้างอินสแตนซ์ FileBackupHelper คุณต้องระบุชื่อไฟล์อย่างน้อย 1 ไฟล์ที่บันทึกไว้ในที่จัดเก็บข้อมูลภายในของแอปตามที่ระบุโดย getFilesDir() ซึ่งเป็นตำแหน่งเดียวกับที่ openFileOutput() เขียนไฟล์
ตัวอย่างเช่น หากต้องการสำรองข้อมูลไฟล์ 2 ไฟล์ชื่อ scores และ stats ตัวแทนการสำรองข้อมูลที่ใช้ BackupAgentHelper จะมีลักษณะดังนี้
Kotlin
// The name of the file
const val TOP_SCORES = "scores"
const val PLAYER_STATS = "stats"
// A key to uniquely identify the set of backup data
const val FILES_BACKUP_KEY = "myfiles"
class MyFileBackupAgent : BackupAgentHelper() {
override fun onCreate() {
// Allocate a helper and add it to the backup agent
FileBackupHelper(this, TOP_SCORES, PLAYER_STATS).also {
addHelper(FILES_BACKUP_KEY, it)
}
}
}
Java
public class MyFileBackupAgent extends BackupAgentHelper {
// The name of the file
static final String TOP_SCORES = "scores";
static final String PLAYER_STATS = "stats";
// A key to uniquely identify the set of backup data
static final String FILES_BACKUP_KEY = "myfiles";
// Allocate a helper and add it to the backup agent
@Override
public void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this,
TOP_SCORES, PLAYER_STATS);
addHelper(FILES_BACKUP_KEY, helper);
}
}
FileBackupHelper มีโค้ดทั้งหมดที่จำเป็นสำหรับการสำรองและกู้คืนไฟล์ที่บันทึกไว้ในที่จัดเก็บข้อมูลภายในของแอป
อย่างไรก็ตาม การอ่านและเขียนไฟล์ในที่จัดเก็บข้อมูลภายในไม่ปลอดภัยต่อเทรด เพื่อให้แน่ใจว่าตัวแทนการสำรองข้อมูลจะไม่อ่านหรือเขียนไฟล์ของคุณพร้อมกับกิจกรรมของคุณ คุณต้องใช้คำสั่งที่ซิงค์กันทุกครั้งที่ทำการอ่านหรือเขียน ตัวอย่างเช่น ในกิจกรรมใดก็ตามที่คุณอ่านและเขียนไฟล์ คุณต้องมีออบเจ็กต์เพื่อใช้เป็นล็อกภายในสำหรับคำสั่งที่ซิงค์ข้อมูล
Kotlin
// Object for intrinsic lock
companion object {
val sDataLock = Any()
}
Java
// Object for intrinsic lock
static final Object sDataLock = new Object();
จากนั้นสร้างคำสั่งที่ซิงค์กับล็อกนี้ทุกครั้งที่คุณอ่านหรือเขียนไฟล์ ตัวอย่างเช่น ต่อไปนี้เป็นคำสั่งที่ซิงค์สำหรับการเขียนคะแนนล่าสุดในเกมลงในไฟล์
Kotlin
try {
synchronized(MyActivity.sDataLock) {
val dataFile = File(filesDir, TOP_SCORES)
RandomAccessFile(dataFile, "rw").apply {
writeInt(score)
}
}
} catch (e: IOException) {
Log.e(TAG, "Unable to write to file")
}
Java
try {
synchronized (MyActivity.sDataLock) {
File dataFile = new File(getFilesDir(), TOP_SCORES);
RandomAccessFile raFile = new RandomAccessFile(dataFile, "rw");
raFile.writeInt(score);
}
} catch (IOException e) {
Log.e(TAG, "Unable to write to file");
}
คุณควรซิงค์คำสั่งอ่านด้วยการล็อกเดียวกัน
จากนั้นใน BackupAgentHelper คุณต้องลบล้าง onBackup() และ onRestore() เพื่อซิงค์การดำเนินการสำรองและกู้คืนข้อมูลด้วยการล็อกภายในเดียวกัน ตัวอย่างเช่น ตัวอย่าง MyFileBackupAgent ก่อนหน้าต้องใช้เมธอดต่อไปนี้
Kotlin
@Throws(IOException::class)
override fun onBackup(
oldState: ParcelFileDescriptor,
data: BackupDataOutput,
newState: ParcelFileDescriptor
) {
// Hold the lock while the FileBackupHelper performs back up
synchronized(MyActivity.sDataLock) {
super.onBackup(oldState, data, newState)
}
}
@Throws(IOException::class)
override fun onRestore(
data: BackupDataInput,
appVersionCode: Int,
newState: ParcelFileDescriptor
) {
// Hold the lock while the FileBackupHelper restores the file
synchronized(MyActivity.sDataLock) {
super.onRestore(data, appVersionCode, newState)
}
}
Java
@Override
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
ParcelFileDescriptor newState) throws IOException {
// Hold the lock while the FileBackupHelper performs back up
synchronized (MyActivity.sDataLock) {
super.onBackup(oldState, data, newState);
}
}
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
// Hold the lock while the FileBackupHelper restores the file
synchronized (MyActivity.sDataLock) {
super.onRestore(data, appVersionCode, newState);
}
}
ขยาย BackupAgent
แอปส่วนใหญ่ไม่จำเป็นต้องขยายคลาส BackupAgent โดยตรง แต่ควรขยาย BackupAgentHelper เพื่อใช้ประโยชน์จากคลาสตัวช่วยในตัวที่สำรองและกู้คืนไฟล์โดยอัตโนมัติ
อย่างไรก็ตาม คุณอาจขยาย BackupAgent โดยตรงเพื่อดำเนินการต่อไปนี้ได้
- กำหนดเวอร์ชันของรูปแบบข้อมูล ตัวอย่างเช่น หากคุณคาดว่าจะต้องแก้ไขรูปแบบที่ใช้เขียนข้อมูลแอป คุณสามารถสร้างตัวแทนการสำรองข้อมูลเพื่อตรวจสอบเวอร์ชันแอปอีกครั้งในระหว่างการดำเนินการกู้คืน และดำเนินการที่จำเป็นเพื่อให้เข้ากันได้หากเวอร์ชันในอุปกรณ์แตกต่างจากเวอร์ชันของข้อมูลสำรอง ดูข้อมูลเพิ่มเติมได้ที่หัวข้อตรวจสอบเวอร์ชันของข้อมูลที่กู้คืน
- ระบุส่วนของข้อมูลที่จะสำรอง คุณสามารถระบุส่วนของข้อมูลที่จะสำรองและวิธีกู้คืนแต่ละส่วนไปยังอุปกรณ์แทนการสำรองข้อมูลทั้งไฟล์ นอกจากนี้ยังช่วยให้คุณจัดการเวอร์ชันต่างๆ ได้ด้วย เนื่องจากคุณอ่านและเขียนข้อมูลเป็นเอนทิตีที่ไม่ซ้ำกัน ไม่ใช่ไฟล์ที่สมบูรณ์
- สำรองข้อมูลในฐานข้อมูล หากคุณมีฐานข้อมูล SQLite ที่ต้องการกู้คืนเมื่อผู้ใช้ติดตั้งแอปอีกครั้ง คุณต้องสร้าง
BackupAgentที่กำหนดเองซึ่งจะอ่านข้อมูลที่เหมาะสมระหว่างการดำเนินการสำรองข้อมูล จากนั้นสร้างตารางและแทรกข้อมูลระหว่างการดำเนินการกู้คืน
หากไม่จำเป็นต้องทำงานก่อนหน้าและต้องการสำรองข้อมูลไฟล์ทั้งหมดจาก SharedPreferences หรือที่จัดเก็บข้อมูลภายใน โปรดดูหัวข้อการขยาย BackupAgentHelper
วิธีการที่จำเป็น
เมื่อสร้าง BackupAgent คุณต้องใช้เมธอด Callback ต่อไปนี้
onBackup()- เครื่องมือจัดการข้อมูลสำรองจะเรียกใช้เมธอดนี้หลังจากที่คุณขอสำรองข้อมูล ในวิธีนี้ คุณจะอ่านข้อมูลแอปจากอุปกรณ์และส่งข้อมูลที่ต้องการสำรองไปยัง Backup Manager ตามที่อธิบายไว้ในทำการสำรองข้อมูล
onRestore()เครื่องมือจัดการการสำรองข้อมูลจะเรียกใช้เมธอดนี้ระหว่างการดำเนินการกู้คืน วิธีนี้จะส่งข้อมูลสำรองซึ่งแอปของคุณสามารถใช้เพื่อกู้คืนสถานะเดิมได้ ตามที่อธิบายไว้ในดำเนินการกู้คืน
ระบบจะเรียกใช้เมธอดนี้เพื่อกู้คืนข้อมูลสำรองเมื่อผู้ใช้ติดตั้งแอปอีกครั้ง แต่แอปของคุณก็สามารถขอการกู้คืนได้เช่นกัน
สำรองข้อมูล
คำขอสำรองข้อมูลจะไม่ส่งผลให้มีการเรียกใช้เมธอด onBackup() ของคุณในทันที แต่ตัวจัดการการสำรองข้อมูลจะรอเวลาที่เหมาะสม แล้วจึงสำรองข้อมูลสำหรับแอปทั้งหมดที่ขอสำรองข้อมูลนับตั้งแต่การสำรองข้อมูลครั้งล่าสุด นี่คือจุดที่คุณต้องระบุข้อมูลแอปให้กับเครื่องมือจัดการการสำรองข้อมูลเพื่อให้สามารถบันทึกข้อมูลลงในพื้นที่เก็บข้อมูลระบบคลาวด์ได้
มีเพียง Backup Manager เท่านั้นที่เรียกใช้เมธอด onBackup() ของตัวแทนการสำรองข้อมูลได้ ทุกครั้งที่ข้อมูลแอปมีการเปลี่ยนแปลงและคุณต้องการสำรองข้อมูล คุณต้องส่งคำขอการดำเนินการสำรองข้อมูลโดยเรียกใช้ dataChanged()
ดูข้อมูลเพิ่มเติมได้ที่ขอข้อมูลสำรอง
เคล็ดลับ: ขณะพัฒนาแอป คุณสามารถเริ่มการดำเนินการสำรองข้อมูลทันทีจากเครื่องมือจัดการการสำรองข้อมูลด้วยเครื่องมือ bmgr
เมื่อ Backup Manager เรียกใช้เมธอด onBackup() ระบบจะส่งพารามิเตอร์ 3 รายการดังนี้
oldStateParcelFileDescriptorแบบเปิดและอ่านอย่างเดียวที่ชี้ไปยังสถานะการสำรองข้อมูลล่าสุดที่แอปของคุณระบุไว้ ข้อมูลนี้ไม่ใช่ข้อมูลสำรองจากพื้นที่เก็บข้อมูลระบบคลาวด์ แต่เป็นการแสดงข้อมูลที่สำรองไว้ในเครื่องเมื่อมีการเรียกใช้onBackup()ครั้งล่าสุดตามที่กำหนดโดยnewStateหรือจากonRestore()onRestore()จะอธิบายไว้ในส่วนถัดไป เนื่องจากonBackup()ไม่อนุญาตให้คุณอ่านข้อมูลสำรองที่มีอยู่ในพื้นที่เก็บข้อมูลระบบคลาวด์ คุณจึงสามารถใช้การแสดงข้อมูลในเครื่องนี้เพื่อระบุว่าข้อมูลมีการเปลี่ยนแปลงหรือไม่นับตั้งแต่การสำรองข้อมูลครั้งล่าสุดdata- ออบเจ็กต์
BackupDataOutputซึ่งคุณใช้เพื่อส่งข้อมูลสำรองไปยัง Backup Manager newStateParcelFileDescriptorแบบเปิดและอ่าน-เขียนที่ชี้ไปยังไฟล์ที่คุณต้องเขียนการนำเสนอข้อมูลที่ส่งไปยังdataการแสดงข้อมูลอาจเป็นการประทับเวลาที่แก้ไขล่าสุดสำหรับไฟล์ของคุณ ระบบจะแสดงผลออบเจ็กต์นี้เป็นoldStateในครั้งถัดไปที่ Backup Manager เรียกใช้เมธอดonBackup()ของคุณ หากคุณไม่เขียนข้อมูลสำรองลงในnewStateoldStateจะชี้ไปยังไฟล์เปล่าในครั้งถัดไปที่เครื่องมือจัดการการสำรองข้อมูลเรียกใช้onBackup()
ใช้พารามิเตอร์เหล่านี้เพื่อใช้เมธอด onBackup() เพื่อทำสิ่งต่อไปนี้
ตรวจสอบว่าข้อมูลมีการเปลี่ยนแปลงนับตั้งแต่การสำรองข้อมูลครั้งล่าสุดหรือไม่โดยเปรียบเทียบ
oldStateกับข้อมูลปัจจุบัน วิธีอ่านข้อมูลในoldStateขึ้นอยู่กับวิธีที่คุณเขียนข้อมูลลงในnewState(ดูขั้นตอนที่ 3) วิธีที่ง่ายที่สุดในการบันทึกสถานะของไฟล์คือการใช้การประทับเวลาที่แก้ไขล่าสุด ตัวอย่างเช่น วิธีอ่านและเปรียบเทียบการประทับเวลาจากoldStateมีดังนี้Kotlin
val instream = FileInputStream(oldState.fileDescriptor) val dataInputStream = DataInputStream(instream) try { // Get the last modified timestamp from the state file and data file val stateModified = dataInputStream.readLong() val fileModified: Long = dataFile.lastModified() if (stateModified != fileModified) { // The file has been modified, so do a backup // Or the time on the device changed, so be safe and do a backup } else { // Don't back up because the file hasn't changed return } } catch (e: IOException) { // Unable to read state file... be safe and do a backup }Java
// Get the oldState input stream FileInputStream instream = new FileInputStream(oldState.getFileDescriptor()); DataInputStream in = new DataInputStream(instream); try { // Get the last modified timestamp from the state file and data file long stateModified = in.readLong(); long fileModified = dataFile.lastModified(); if (stateModified != fileModified) { // The file has been modified, so do a backup // Or the time on the device changed, so be safe and do a backup } else { // Don't back up because the file hasn't changed return; } } catch (IOException e) { // Unable to read state file... be safe and do a backup }หากไม่มีการเปลี่ยนแปลงและคุณไม่จำเป็นต้องสำรองข้อมูล ให้ข้ามไปยังขั้นตอนที่ 3
หากข้อมูลมีการเปลี่ยนแปลงเมื่อเทียบกับ
oldStateให้เขียนข้อมูลปัจจุบันลงในdataเพื่อสำรองข้อมูลไปยังพื้นที่เก็บข้อมูลระบบคลาวด์คุณต้องเขียนข้อมูลแต่ละส่วนเป็นเอนทิตีใน
BackupDataOutputเอนทิตีคือระเบียนข้อมูลไบนารีแบบแฟลตที่ระบุด้วยสตริงคีย์ที่ไม่ซ้ำกัน ดังนั้น ชุดข้อมูลที่คุณสำรองข้อมูลจึงเป็นชุดคู่คีย์-ค่าในเชิงแนวคิดหากต้องการเพิ่มเอนทิตีลงในชุดข้อมูลสำรอง คุณต้องทำดังนี้
เรียกใช้
writeEntityHeader()โดยส่งคีย์สตริงที่ไม่ซ้ำกันสำหรับข้อมูลที่คุณกำลังจะเขียนและขนาดข้อมูลเรียกใช้
writeEntityData()โดยส่งบัฟเฟอร์ไบต์ที่มีข้อมูลของคุณและจำนวนไบต์ที่จะเขียนจากบัฟเฟอร์ ซึ่งควรตรงกับขนาดที่ส่งไปยังwriteEntityHeader()
ตัวอย่างเช่น โค้ดต่อไปนี้จะแปลงข้อมูลบางอย่างให้เป็นสตรีมไบต์และเขียนลงในเอนทิตีเดียว
Kotlin
val buffer: ByteArray = ByteArrayOutputStream().run { DataOutputStream(this).apply { writeInt(playerName) writeInt(playerScore) } toByteArray() } val len: Int = buffer.size data.apply { writeEntityHeader(TOPSCORE_BACKUP_KEY, len) writeEntityData(buffer, len) }Java
// Create buffer stream and data output stream for our data ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); DataOutputStream outWriter = new DataOutputStream(bufStream); // Write structured data outWriter.writeUTF(playerName); outWriter.writeInt(playerScore); // Send the data to the Backup Manager using the BackupDataOutput byte[] buffer = bufStream.toByteArray(); int len = buffer.length; data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len); data.writeEntityData(buffer, len);ดำเนินการนี้กับข้อมูลแต่ละรายการที่ต้องการสำรองข้อมูล คุณจะแบ่งข้อมูลออกเป็นเอนทิตีอย่างไรก็ได้ตามต้องการ หรืออาจใช้เพียงเอนทิตีเดียวก็ได้
ไม่ว่าคุณจะสำรองข้อมูล (ในขั้นตอนที่ 2) หรือไม่ ให้เขียนการนำเสนอข้อมูลปัจจุบันลงใน
newStateParcelFileDescriptorเครื่องมือจัดการการสำรองข้อมูลจะเก็บออบเจ็กต์นี้ไว้ในเครื่องเพื่อแสดงข้อมูลที่สำรองไว้ในปัจจุบัน โดยจะส่งค่านี้กลับมาให้คุณเป็นoldStateในครั้งถัดไปที่เรียกใช้onBackup()เพื่อให้คุณพิจารณาได้ว่าจำเป็นต้องสำรองข้อมูลอีกหรือไม่ ตามที่จัดการในขั้นตอนที่ 1 หากคุณไม่เขียนสถานะข้อมูลปัจจุบันลงในไฟล์นี้oldStateจะว่างเปล่าในระหว่างการเรียกกลับครั้งถัดไปตัวอย่างต่อไปนี้จะบันทึกการแสดงข้อมูลปัจจุบันลงใน
newStateโดยใช้การประทับเวลาที่แก้ไขล่าสุดของไฟล์Kotlin
val modified = dataFile.lastModified() FileOutputStream(newState.fileDescriptor).also { DataOutputStream(it).apply { writeLong(modified) } }Java
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor()); DataOutputStream out = new DataOutputStream(outstream); long modified = dataFile.lastModified(); out.writeLong(modified);
ทำการกู้คืน
เมื่อถึงเวลาคืนค่าข้อมูลแอป ตัวจัดการการสำรองข้อมูลจะเรียกใช้เมธอด onRestore() ของตัวแทนการสำรองข้อมูล เมื่อเรียกใช้เมธอดนี้ ตัวจัดการการสำรองข้อมูลจะส่งข้อมูลสำรองเพื่อให้คุณกู้คืนข้อมูลลงในอุปกรณ์ได้
มีเพียง Backup Manager เท่านั้นที่เรียกใช้ onRestore() ได้ ซึ่งจะเกิดขึ้นโดยอัตโนมัติเมื่อระบบติดตั้งแอปและพบข้อมูลสำรองที่มีอยู่
เมื่อ Backup Manager เรียกใช้เมธอด onRestore() ระบบจะส่งพารามิเตอร์ 3 รายการดังนี้
data- ออบเจ็กต์
BackupDataInputซึ่งช่วยให้คุณอ่านข้อมูลสำรองได้ appVersionCode- จำนวนเต็มที่แสดงค่าของแอตทริบิวต์ไฟล์ Manifest
android:versionCodeของแอป ณ เวลาที่สำรองข้อมูลนี้ คุณสามารถใช้ข้อมูลนี้เพื่อตรวจสอบเวอร์ชันปัจจุบันของแอปและพิจารณาว่ารูปแบบข้อมูลเข้ากันได้หรือไม่ ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ฟังก์ชันนี้เพื่อจัดการข้อมูลการกู้คืนเวอร์ชันต่างๆ ได้ที่ตรวจสอบเวอร์ชันข้อมูลการกู้คืน newStateParcelFileDescriptorแบบเปิดที่อ่านและเขียนได้ซึ่งชี้ไปยังไฟล์ที่คุณต้องเขียนสถานะการสำรองข้อมูลขั้นสุดท้ายที่ระบุไว้ด้วยdataระบบจะแสดงผลออบเจ็กต์นี้เป็นoldStateในครั้งถัดไปที่มีการเรียกใช้onBackup()โปรดทราบว่าคุณต้องเขียนออบเจ็กต์newStateเดียวกันใน CallbackonBackup()ด้วย การดำเนินการนี้จะช่วยให้มั่นใจว่าออบเจ็กต์oldStateที่ระบุให้กับonBackup()นั้นถูกต้อง แม้ว่าจะเป็นครั้งแรกที่มีการเรียกใช้onBackup()หลังจากกู้คืนอุปกรณ์แล้วก็ตาม
ในการติดตั้งใช้งาน onRestore() คุณควรเรียกใช้
readNextHeader()
ใน data เพื่อทำซ้ำผ่านเอนทิตีทั้งหมดในชุดข้อมูล สำหรับเอนทิตีแต่ละรายการที่พบ ให้ทำดังนี้
- รับคีย์เอนทิตีด้วย
getKey() เปรียบเทียบคีย์เอนทิตีกับรายการค่าคีย์ที่รู้จักซึ่งคุณควรประกาศเป็นสตริงแบบคงที่ขั้นสุดท้ายภายในคลาส
BackupAgentเมื่อคีย์ตรงกับสตริงคีย์ที่รู้จัก ให้ป้อนคำสั่งเพื่อดึงข้อมูลเอนทิตีและบันทึกลงในอุปกรณ์ ดังนี้- รับขนาดข้อมูลเอนทิตีด้วย
getDataSize()และสร้างอาร์เรย์ไบต์ขนาดดังกล่าว - เรียกใช้
readEntityData()และส่งอาร์เรย์ไบต์ซึ่งเป็นตำแหน่งที่ข้อมูลจะไป และระบุออฟเซ็ตเริ่มต้นและขนาดที่จะอ่าน - ตอนนี้อาร์เรย์ไบต์ของคุณเต็มแล้ว อ่านข้อมูลและเขียนลงในอุปกรณ์ตามที่คุณต้องการ
- รับขนาดข้อมูลเอนทิตีด้วย
หลังจากอ่านและเขียนข้อมูลกลับไปยังอุปกรณ์แล้ว ให้เขียนสถานะของข้อมูลลงในพารามิเตอร์
newStateเช่นเดียวกับที่ทำในระหว่างonBackup()
ตัวอย่างเช่น วิธีคืนค่าข้อมูลที่สำรองไว้ตามตัวอย่างในส่วนก่อนหน้ามีดังนี้
Kotlin
@Throws(IOException::class)
override fun onRestore(data: BackupDataInput, appVersionCode: Int,
newState: ParcelFileDescriptor) {
with(data) {
// There should be only one entity, but the safest
// way to consume it is using a while loop
while (readNextHeader()) {
when(key) {
TOPSCORE_BACKUP_KEY -> {
val dataBuf = ByteArray(dataSize).also {
readEntityData(it, 0, dataSize)
}
ByteArrayInputStream(dataBuf).also {
DataInputStream(it).apply {
// Read the player name and score from the backup data
playerName = readUTF()
playerScore = readInt()
}
// Record the score on the device (to a file or something)
recordScore(playerName, playerScore)
}
}
else -> skipEntityData()
}
}
}
// Finally, write to the state blob (newState) that describes the restored data
FileOutputStream(newState.fileDescriptor).also {
DataOutputStream(it).apply {
writeUTF(playerName)
writeInt(mPlayerScore)
}
}
}
Java
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
// There should be only one entity, but the safest
// way to consume it is using a while loop
while (data.readNextHeader()) {
String key = data.getKey();
int dataSize = data.getDataSize();
// If the key is ours (for saving top score). Note this key was used when
// we wrote the backup entity header
if (TOPSCORE_BACKUP_KEY.equals(key)) {
// Create an input stream for the BackupDataInput
byte[] dataBuf = new byte[dataSize];
data.readEntityData(dataBuf, 0, dataSize);
ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
DataInputStream in = new DataInputStream(baStream);
// Read the player name and score from the backup data
playerName = in.readUTF();
playerScore = in.readInt();
// Record the score on the device (to a file or something)
recordScore(playerName, playerScore);
} else {
// We don't know this entity key. Skip it. (Shouldn't happen.)
data.skipEntityData();
}
}
// Finally, write to the state blob (newState) that describes the restored data
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
DataOutputStream out = new DataOutputStream(outstream);
out.writeUTF(playerName);
out.writeInt(mPlayerScore);
}
ในตัวอย่างนี้ ไม่ได้ใช้พารามิเตอร์ appVersionCode ที่ส่งไปยัง onRestore() อย่างไรก็ตาม คุณอาจต้องการใช้หากเลือกที่จะสำรองข้อมูลเมื่อแอปเวอร์ชันของผู้ใช้ย้อนกลับไปเป็นเวอร์ชันก่อนหน้า (เช่น ผู้ใช้เปลี่ยนจากแอปเวอร์ชัน 1.5 เป็น 1.0) ดูข้อมูลเพิ่มเติมได้ในส่วนถัดไป
ตรวจสอบเวอร์ชันของข้อมูลที่กู้คืน
เมื่อตัวจัดการการสำรองข้อมูลบันทึกข้อมูลของคุณลงในพื้นที่เก็บข้อมูลระบบคลาวด์ ระบบจะรวมเวอร์ชันของแอปโดยอัตโนมัติตามที่กำหนดโดยแอตทริบิวต์ android:versionCode ของไฟล์ Manifest ก่อนที่เครื่องมือจัดการการสำรองข้อมูลจะเรียกใช้ตัวแทนการสำรองข้อมูลเพื่อกู้คืนข้อมูล เครื่องมือจะดู android:versionCode ของแอปที่ติดตั้งไว้และเปรียบเทียบกับค่าที่บันทึกไว้ในชุดข้อมูลการกู้คืน หากเวอร์ชันที่บันทึกไว้ในชุดข้อมูลการกู้คืนใหม่กว่าเวอร์ชันแอปในอุปกรณ์ แสดงว่าผู้ใช้ดาวน์เกรดแอป ในกรณีนี้ Backup Manager จะยกเลิกการดำเนินการกู้คืนสำหรับแอปของคุณและไม่เรียกใช้เมธอด onRestore() เนื่องจากระบบถือว่าชุดการกู้คืนไม่มีความหมายสำหรับเวอร์ชันที่เก่ากว่า
คุณลบล้างลักษณะการทำงานนี้ได้โดยใช้แอตทริบิวต์ android:restoreAnyVersion ดังนี้
false(ค่าเริ่มต้น): เครื่องมือจัดการการสำรองข้อมูลจะยกเลิกการดำเนินการกู้คืนหากเวอร์ชันที่บันทึกไว้ในชุดข้อมูลการกู้คืนใหม่กว่าเวอร์ชันของแอปในอุปกรณ์true: เครื่องมือจัดการการสำรองข้อมูลจะละเว้นandroid:versionCodeและเรียกใช้เมธอดonRestore()ของคุณในทุกกรณี เพื่อให้คุณตรวจสอบความแตกต่างของเวอร์ชันและทำให้ข้อมูลเข้ากันได้ด้วยตนเอง
เพื่อช่วยคุณจัดการเวอร์ชันต่างๆ ในระหว่างการดำเนินการกู้คืน เมธอด onRestore() จะส่งรหัสเวอร์ชันที่รวมอยู่ในชุดข้อมูลการกู้คืนเป็นพารามิเตอร์ appVersionCode จากนั้นคุณจะค้นหารหัสเวอร์ชันของแอปปัจจุบันได้ด้วยช่อง PackageInfo.versionCode เช่น
Kotlin
val info: PackageInfo? = try {
packageManager.getPackageInfo(packageName, 0)
} catch (e: PackageManager.NameNotFoundException) {
null
}
val version: Int = info?.versionCode ?: 0
Java
PackageInfo info;
try {
String name = getPackageName();
info = getPackageManager().getPackageInfo(name, 0);
} catch (NameNotFoundException nnfe) {
info = null;
}
int version;
if (info != null) {
version = info.versionCode;
}
จากนั้นเปรียบเทียบ version ที่ได้จาก PackageInfo กับ appVersionCode ที่ส่งไปยัง onRestore()
ขอข้อมูลสำรอง
คุณสามารถขอให้มีการดำเนินการสำรองข้อมูลได้ทุกเมื่อโดยโทรหา dataChanged() เมธอดนี้จะแจ้งให้ตัวจัดการการสำรองข้อมูลทราบว่าคุณต้องการสำรองข้อมูลโดยใช้ตัวแทนการสำรองข้อมูล จากนั้นเครื่องมือจัดการการสำรองข้อมูลจะเรียกใช้เมธอด onBackup() ของตัวแทนการสำรองข้อมูลในอนาคต โดยปกติแล้ว คุณควรขอสำรองข้อมูลทุกครั้งที่มีการเปลี่ยนแปลงข้อมูล (เช่น เมื่อผู้ใช้เปลี่ยนค่ากำหนดของแอปที่คุณต้องการสำรองข้อมูล) หากคุณเรียกใช้ dataChanged() หลายครั้งก่อนที่ Backup Manager จะขอข้อมูลสำรองจาก Agent ของคุณ Agent จะยังคงได้รับการเรียกใช้ onBackup() เพียงครั้งเดียว
ขอให้กู้คืน
ในระหว่างอายุการใช้งานปกติของแอป คุณไม่จำเป็นต้องขอการดำเนินการกู้คืน ระบบจะตรวจหาข้อมูลสำรองและทำการกู้คืนโดยอัตโนมัติเมื่อติดตั้งแอป
ย้ายข้อมูลไปยังการสำรองข้อมูลอัตโนมัติ
คุณสามารถเปลี่ยนแอปไปใช้การสำรองข้อมูลแบบเต็มได้โดยตั้งค่า android:fullBackupOnly เป็น true ในองค์ประกอบ <application> ในไฟล์ Manifest เมื่อทำงานในอุปกรณ์ที่ใช้ Android 5.1 (ระดับ API 22) หรือต่ำกว่า แอปจะละเว้นค่านี้ในไฟล์ Manifest และทำการสำรองข้อมูลคีย์-ค่าต่อไป เมื่อทำงานในอุปกรณ์ที่ใช้ Android 6.0 (ระดับ API 23) ขึ้นไป แอปจะทำการสำรองข้อมูลอัตโนมัติแทนการสำรองข้อมูลคีย์-ค่า
ความเป็นส่วนตัวของผู้ใช้
Google ทราบดีถึงความไว้วางใจที่ผู้ใช้มีให้และหน้าที่ความรับผิดชอบในการปกป้องความเป็นส่วนตัวของผู้ใช้ Google จะส่งข้อมูลสำรองไปยังและจากเซิร์ฟเวอร์ของ Google อย่างปลอดภัยเพื่อให้บริการฟีเจอร์สำรองและกู้คืนข้อมูล Google จะถือว่าข้อมูลนี้เป็นข้อมูลส่วนบุคคลตามนโยบายความเป็นส่วนตัวของ Google
นอกจากนี้ ผู้ใช้ยังปิดใช้ฟังก์ชันการสำรองข้อมูลผ่านการตั้งค่าการสำรองข้อมูลของระบบ Android ได้ด้วย เมื่อผู้ใช้ปิดใช้การสำรองข้อมูล Android Backup Service จะลบข้อมูลสำรองที่บันทึกไว้ทั้งหมด ผู้ใช้สามารถเปิดใช้การสำรองข้อมูลในอุปกรณ์อีกครั้งได้ แต่ Android Backup Service จะไม่กู้คืนข้อมูลที่ลบไปก่อนหน้านี้