爲了備份應用數據,你須要實現一個 backup agent. 它用來爲BackupManager 提供你想要備份的數據,在你從新安裝應用時恢復數據。BackupManager 經過backup transport 處理和雲存儲相關的數據業務,經過你的backup agent 處理設備上的數據相關的業務。android
BackupAgent實現步驟:shell
在 manifest 文件中聲明 android:backupAgent 屬性。數據庫
經過backup服務註冊你的應用。谷歌爲大多數 Android 設備提供了 Android Backup Service,你須要經過這個服務註冊你的應用。其餘的雲服務也須要註冊。api
定義你的 backup agent:安全
擴展 BackupAgent
重寫 onBackup() onRestore()app
擴展 BackupAgentHelper
須要使用多個helper對象自動完成備份及恢復。
會備份整個文件。dom
在application
標籤中聲明android:backupAgent
.ide
<manifest ... > ... <application android:label="MyApplication" android:backupAgent="MyBackupAgent"> <activity ... > ... </activity> </application> </manifest>
android:restoreAnyVersion
默認值爲false
, 設爲true
則會在該應用的任何版本恢復數據。工具
不一樣的設備對 backup 的支持不一樣。oop
<application android:label="MyApplication" android:backupAgent="MyBackupAgent"> ... <meta-data android:name="com.google.android.backup.api_key" android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" /> </application>
通常狀況下,由於BackupAgentHelper
比BackupAgent
更方便,因此儘量使用前者。
然而,若是有如下需求,仍是要經過BackupAgent
來實現:
對數據進行版本控制
並不想備份整個數據文件
備份數據庫中的數據
若是你想要備份SharedPreferences
和內部存儲
中的整個文件,簡單地使用BackupAgentHelper
便可。
oldState
上一次備份的狀態,主要是FileDescriptor
// 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 = mDataFile.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 }
data
要備份的數據,經過byte
字節流的方式存儲
// Create buffer stream and data output stream for our data ByteArrayOutputStream bufStream = new ByteArrayOutputStream(); DataOutputStream outWriter = new DataOutputStream(bufStream); // Write structured data outWriter.writeUTF(mPlayerName); outWriter.writeInt(mPlayerScore); // 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);
newState
本次備份的狀態,做爲下次備份時的oldState
data
用來恢復數據的 `BackupDataInput`.
appVersionCode
android:versionCode
newState
恢復後,須要把data裏的ParcelFileDescriptor
寫到newState
中,它會如下次onBackup
的oldState
被用到。
@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 mPlayerName = in.readUTF(); mPlayerScore = in.readInt(); // Record the score on the device (to a file or something) recordScore(mPlayerName, mPlayerScore); } 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(mPlayerName); out.writeInt(mPlayerScore); }
SharedPreferencesBackupHelper
FileBackupHelper
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); } }
Note:
SharedPreferences
are threadsafe, so you can safely read and write the shared preferences file from your backup agent and other activities.
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); } }
非線程安全,須要手動加鎖
// Object for intrinsic lock static final Object sDataLock = new Object(); 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"); } @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); } }
android:versionCode
BackupManager
恢復數據前會檢查versionCode
字段,若是待恢復的版本高於當前應用版本,BackupManager
不會調用onRestore()
來恢復數據。android:restoreAnyVersion
設定true
orfalse
指明你是否但願經過應用的版原本決定是否恢復數據。設爲true
,那麼BackupManager
將不會去檢查android:versionCode
,而是調用你的onRestore()
方法。
你能夠經過下面的方法來獲取appVersionCode
.
PackageInfo info; try { String name = getPackageName(); info = getPackageManager().getPackageInfo(name,0); } catch (NameNotFoundException nnfe) { info = null; } int version; if (info != null) { version = info.versionCode; }
使用dataChanged()
來請求備份,這個不會當即執行,會在將來某個合適的時間內執行
開發時使用bmgr
工具來隨時備份
自動檢測備份數據
requestRestore()
bmgr
工具
安裝應用
肯定備份功能可用
使用模擬器adb shell bmgr enable true
If using a device, open the system Settings, select Backup & reset, then enable Back up my data and Automatic restore.
在用戶改變數據的地方調用dataChanged()
而後執行:adb shell bmgr backup your.package.name
‘
初始化備份操做
adb shell bmgr run
卸載應用
adb uninstall your.package.name
從新安裝