編輯:系統備份
最近我在閱讀Android Developer上的文章,本文是對其中一篇Data Backup的翻譯。希望可以通過翻譯英文技術文章提高自己閱讀英文文檔的水平,如果有不妥的地方,希望指出,謝謝~因為這個涉及到google服務,可能目前在國內大家不怎麼去使用它。
Android的備份服務為了給我們的應用數據和配置提供還原的功能,它允許我們把我們的應用數據拷貝到遠程的“雲”存儲上去。如果一個用戶在他的手機上恢復了出廠設置或者換了一部新的Android設備,當開發者的應用被重新安裝的時候,系統將會自動修復你的已經備份的數據。通過這個方式,你的用戶沒必要去重新生成以前的數據或者應用的配置。這個過程是完全透明的並且將不會影響你的App的功能或者用戶體驗。
在備份操作的過程中(你的應用可以請求的操作),Android的備份管理(BackupManager)去查詢你的應用的備用數據,並且將數據提交給備份傳輸,備份傳輸將會幫我們把數據發送給雲存儲。在我們恢復數據的操作過程中,Android備份管理從我們的備份傳輸中去恢復數據並且把數據返回到我們的應用以便應用可以在設備上去恢復數據。對你的應用來說,要求數據的還原是可能的,但是這個操作不應該是必要的-當你的應用被安裝時,Android會自動進行還原操作並且還原與用戶有關的備份數據。備份數據還原的主要場景是:當用戶重置了他們的設備或者使用了一個新的Android設備,同時他們之前已經安裝過的應用需要重新安裝。
注意:備份服務不是為與其他客戶端同步應用數據或者用於存儲在應用的運行周期內使用的數據而設計的。你不能立即(隨時)讀寫備份數據並且除了通過Android備份管理提供的API之外,其他途徑都不能訪問備份數據。
備份傳輸是Android備份框架的客戶端組件,它可以被設備廠商和服務提供者所定制。在不同設備上備份傳輸可能是不同的,並且在任何給定的設備上哪種備份傳輸是可用的對於我們的應用來說是透明的。備份管理的API把你的應用和在給定設備上可用的實際的備份傳輸分隔開來-你的應用通過一組固定的API與Android傳輸管理組件通訊,而不是直接去操作底層的未封裝的傳輸。
Android數據備份並不保證在每個Android設備上都是可用的。但是,當設備不支持備份傳輸的時候,並不會對我們的應用產生什麼不利的影響。如果你相信用戶將會在你的應用中從數據備份功能獲益,你可以像在文檔中描述的那樣去實現它,測試它,發布你的應用,而不用去關心每個Android設備數據備份的具體實現。當你的應用在不支持Android數據備份的設備上運行時,你的應用可以正常運行,但是將不再接收從Android備份管理到備份數據的回調。
盡管你可能不知道目前備份所使用的是哪一種傳輸,有一點是可以確定的:你的備份數據 不會被同一個設備上的其它App所讀取。在你的備份操作期間,只有Android備份管理和相應的備份傳輸有權限去讀取你的數據。
提示:因為在每部設備上的雲存儲和傳輸服務都可能是不同的,當你使用備份的時候,Android不會保證你的數據的絕對安全性。當使用備份去存儲例如用戶名和密碼這樣的敏感數據的時候,你通常都要保持謹慎。
為了備份你的應用數據,你需要去實現一個備份代理(backup agent)。備份管理調用你的備份代理去提供你想備份的數據。當應用被重新安裝的時候,備份代理同樣被調用去還原你的備份數據。備份管理處理所有與雲存儲交互的數據(使用備份傳輸),並且你的備份代理處理你的設備上的所有的數據事務。
為了實現備份代理,你必須:
1.在 manifest文件裡用android:backupAgent屬性聲明你的備份代理。
2.為你的應用注冊一個備份service。Google為大部分Android設備提供了Android Backup Service 作為我們的備份service,我們必須要在我們的應用裡注冊它才能確保service的使用。任何其他可用的備份服務將也有可能需要你去注冊以便你在它們的服務器上存儲你的數據。
3.通過以下的方式都可以定義備份代理:
a.擴展備份代理(Extending BackupAgent):
BackupAgent類提供了核心接口用於你的應用與備份管理的通信。如果你直接擴展了這個類,你必須重寫onBackup() 和onRestore()方法去處理備份和還原你的數據。
或
b.擴展備份代理輔助類(Extending BackupAgentHelper):
BackupAgentHelper類為BackupAgent類提供了便捷的包裝,它最大程度地減少了你所要寫的代碼量。在BackupAgentHelper裡,你必須使用一個或多個”helper”對象,它會自動備份和還原某種類型的數據。所以你不必一定實現onBackup() 和onRestore()方法。
Android目前提供了備份幫助類,它會從SharedPreferences和internal storage中去備份和還原完整的文件。
這是最簡單的一步,所以一旦你確認了你的備份代理類的名稱,在Manifest文件的<application>標簽裡用android:backupAgent屬性去聲明它。
例如:
...
...
另一個你可能會使用的屬性是android:restoreAnyVersion。這個屬性使用一個boolean值去表明你是否想去還原應用的數據,而不管產生備份數據的版本和當前版本的比較。(它的默認值是false)。請看檢查還原數據的版本獲取更多信息。
注意:因為你使用的備份服務和 API只有在API版本8(Android 2.2)或更高的時候是可用的,所以你必須同時設置你的android:minSdkVersion 屬性為8。
對於大部分2.2或以上的設備來說,Google提供了帶Android Backup Service的備份傳輸。
為了使你的應用能夠使用Android備份服務( Android Backup Service),你必須在你的應用裡注冊一個帶 Backup Service 秘鑰的service,並且在你的Manifest文件裡聲明這個秘鑰。
為了獲取你的備份服務秘鑰,你需要注冊Android備份服務。當你注冊後,你會得到一個秘鑰和一段 XML代碼,你必須把它們用標簽包含起來。例如:
...
android:name必須是”com.google.android.backup.api_key”,並且android:value必須是從Android備份服務注冊得到的秘鑰才可以。
如果你有多個應用,你必須使用各自的包名去注冊每一個應用以便使用Android的備份服務。
注意:由android備份服務提供的備份傳輸並不是在所有Android設備上都是保證能使用的。有的設備使用另一種方式支持備份,有的設備完全不支持備份,並且你的應用不會知道你在當前設備上使用的是哪種傳輸。但是,如果你為你的應用實現了備份,你通常應該保留一個備份服務秘鑰以便你的應用能夠使用可用的Android備份傳輸服務。如果你的設備不能使用Android備份服務,”< meta-data >” 裡的帶秘鑰的元素將會被自動忽視。
大多數Android應用不需要直接擴展BackupAgent類,而是應該使用extend BackupAgentHelper 去使用可以自動備份和還原文件的內嵌類。但是,如果你需要如下的操作,你可能需要直接擴展BackupAgent類:
給你的數據設定版本。例如,如果你想你修復你寫入應用數據的格式,在還原操作期間,你需要使用一個備份代理去反復檢查你的應用版本。如果你設備上的應用版本與備份的版本是不同的,你需要做一些必要的兼容操作。請看檢查還原數據版本去獲取更多的信息。 與備份整個文件不同的是,你可以指定數據裡哪一部分會被備份並且每個需要備份的部分是如何還原到設備上的。(這可以幫助你管理不同的版本,因為通過不同的特殊的標示去讀寫數據而不是整個文件) 在數據庫裡備份數據。如果當用戶重新安裝了你的App的時候,你有SQLite數據庫數據需要還原,你需要一個自定義的備份代理去讀取數據,並且創建你的表,把數據插入進去。如果你不需要進行以上的操作並且需要從SharedPreferences和內部存儲去備份完整的文件,你應該跳到擴展BackupAgentHelper類。
當你使用擴展BackupAgent類去備份數據,你必須實現如下的回調函數:
onBackup():
在你請求備份之後,備份管理調用了這個方法。在這個方法裡,你從設備上讀取應用數據並且把你想備份的數據傳給Android備份管理,像下文操作備份那樣描述的那樣。
onRestore():
在還原期間,Android備份管理調用這個方法。(你可以自己請求還原操作,但是當用戶重新安裝了你的應用時,系統將自動進行備份數據的還原操作。)當這個方法被調用的時候,備份管理將會傳遞給應用備份數據,就像下文進行還原描述的那樣。
當你正在備份你的應用數據時,備份管理調用了你的onBackup方法。你需要在這裡提供你的應用數據給備份管理器以便你的數據能夠存儲到雲存儲上去。
只有Android的備份管理可以調用你的onBackup方法。每次當你的應用數據變更並且你想進行備份的時候,你必須調用dataChanged()去請求備份操作。(看請求備份去獲取更多信息)一個備份請求不會立刻調用你的onBackup()方法。相反地,備份管理將會等待一個合適的時間,然後為所有的請求數據備份的應用進行備份。
提示:當開發你的應用的時候,你可以使用bmgr tool去發起一個即刻的來自備份管理的備份操作。
當備份管理調用了你的onBackup()方法,它傳遞了三個參數:
public abstract void onBackup (ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)
oldState:
一個只讀的ParcelFileDescriptor ,它指向由我們的應用提供的上一次備份的狀態。它不是來自雲存儲的備份數據,而是上次onBackup函數被調用時備份的本地數據的表示(像如下newState定義的那樣,或者onRestore()-在下一個章節有更多關於它的介紹)。因為onBackup()方法不允許你去讀取雲存儲上的備份數據,你可以用這個參數去判斷你自從上一次備份後是否修改了你的本地數據。
data:
一個BackupDataOutput對象,你使用它去向備份管理傳遞你的備份數據。
newState:
一個可讀寫的ParcelFileDescriptor, 它指向一個文件,這個文件你必須記錄你需要傳輸的數據的標記。(原文:An open, read/write ParcelFileDescriptor pointing to a file in which you must write a representation of the data that you delivered to data)(一個標記可以簡化為你的文件的最後一次修改的時間戳)當下次備份管理調用onBackup()函數的時候,這個對象作為oldState參數傳入。如果你不把你的備份數據寫到newState裡,當下次備份管理調用onBackup()函數的時候,oldState將會指向一個空的文件。
使用這些參數,你可以實現你的onBackup() 方法去做下面的事:
1.通過比較oldState和你現在的數據去判斷自從上一次備份後數據是否發生改變。你如何讀取oldState裡面的數據取決於你當初如何把它存進newState(見步驟3)。最簡單的去記錄文件狀態的方式是使用它最近一次變更的時間戳。例如下面:
// 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
}
如果沒有數據變更,你沒必要進行備份,直接跳到第三步。
2.如果你的數據變更了,把你的數據寫到 data 參數裡,並且把它備份到雲存儲上。
你必須把每一塊數據作為一個實體寫在BackupDataOutput裡。每個實體都是平整的二進制數據記錄,並且每個都對應一個獨一無二的字符串。因此,你緩存的數據在概念上可以理解為key-value類型存儲的數據。
為了在你的備份數據集合裡添加一個實體,你必須:
1.調用writeEntityHeader(),根據你要備份的數據和它的大小來傳遞一個特殊的字符串。
2.調用writeEntityData(),傳遞了一個字節緩沖區,它包含了你的數據和從緩沖區裡需要寫入的字節數(在這裡應該和傳遞給writeEntityHeader()的大小匹配)。
例如,如下的代碼把一些數據轉換成了字節流,並且把它們寫到了一個單獨的實體裡:
// 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);
對你的每一塊你想備份的數據使用這段代碼。如何分配你的數據到不同的實體裡取決於你自己(有可能你只需要一個實體)。
3.無論你是否執行了備份(步驟2),向參數newState ParcelFileDescriptor寫入當前數據的一個標示。備份管理本地保留了這個對象作為備份數據的標識。當下次調用onBackup()時,這個對象最為oldState參數傳遞以便你決定是否備份是必要的(像步驟1處理的那樣)。如果你不寫入當前的數據狀態,oldState參數將會在下次回調是空值。
下面的例子存儲了一個使用文件最後一次修改的時間戳的當前數據的標識到newState:
FileOutputStream outstream = new FileOutputStream(newState.getFileDescriptor());
DataOutputStream out = new DataOutputStream(outstream);
long modified = mDataFile.lastModified();
out.writeLong(modified);
注意:如果你的應用數據被存儲到一個文件裡,當你訪問文件的時候,確保你使用的是同步代碼塊以便你的備份代理不會在你的應用裡的Activity修改這個文件的時候去讀取它。
當你想還原你的應用數據時,備份管理調用你的備份代理的onRestore()方法。當它調用這個方法時,備份管理將會傳遞你的數據以便你可以在設備上還原備份數據。
只有Android備份管理可以調用onRestore()方法,當系統在安裝你的應用和找到存在的備份數據時將會被自動調用。但是,你可以通過調用requestRestore()去為你的應用手動請求數據還原操作。
注意:在開發你的應用的過程中,你也可以通過bmgr tool去進行還原操作的請求。
當備份管理調用你的onRestore()方法的時候,它傳遞了三個參數:
public abstract void onRestore (BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
data
BackupDataInput,通過它去讀取你的備份數據。
appVersionCode
一個值為manifest中屬性android:versionCode的整數,當數據被備份的時候它被使用。你可以使用它去反復檢查當前版本去決定數據格式是否完整。關於使用這個區處理不同版本的數據還原問題,去看下文的檢查還原數據版本去獲取更多的信息。
newState
一個可讀寫的ParcelFileDescriptor,指向一個文件,在這個文件裡,你必須寫入由data參數提供的最終的備份狀態。當下一次onBackup()函數被調用的時候,這個對象被當做oldState返回。你還要在onBackup()回調裡寫入相同的newState對象-保證提供給onBackup()的oldState參數是有效的,即使是onBackup()是第一次被調用。
在你的onRestore()的實現裡,你應該對data參數調用readNextHeader()方法去遍歷set集合中的全部備份數據實體。對於每個數據實體,進行如下操作:
1.用getKey()方法去獲取實例的key值。
2.用這個秘鑰去和一組已知的秘鑰比較,這一組秘鑰是你在你的BackupAgent類裡定義的字符串常量。當其中之一匹配的時候,進入相應的代碼塊,提取並且把數據存到你的設備裡:
(1)用getDataSize() 獲取數據大小並且創建一個字節數組。
(2)調用readEntityData(),並且把字節數組傳給它,數組將會是數據的歸處並且確認起始偏移和需要讀取的大小。
(3)在你的數組包含了數據之後,你就可以把它讀寫到設備上。
3.在你讀寫完數據之後,把你的數據狀態寫入newState參數,就像你在onBackup()做的一樣。
例如,下文是如何還原在上文的例子裡備份的數據:
@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);
}
在這個例子裡,傳遞給onRestore()的appVersionCode參數沒有被使用。但是,如果你在用戶的應用版本落後的時候選擇去備份的話,你有可能將去使用onRestore()函數(例如,用戶從1.5版本到1.0版本)。去查看檢查還原數據版本以獲取更多的信息。
關於備份代理的例子,詳見備份還原實例應用的ExampleAgent類。
如果你想備份完整的文件,你應該使用備份代理輔助類去創建備份代理(不管是SharedPreferences還是內部存儲)。用備份代理輔助類創建自己的備份代理需要的代碼遠遠少於擴展代理,因為你不需要實現onBackup()和onRestore()方法。
你的備份代理輔助類的實現必須使用一個或多個備份助手。備份助手是一個專門的組件,備份輔助類召集備份助手去進行備份和為特定類型的數據進行還原操作。Android框架目前提供了兩個助手:
你可以在你的備份輔助類中包含多個上文所示的助手,你必須在onCreate()的時候做下面的操作:
1.給需要的輔助類生成一個實例。在類的構造函數裡,你必須要指定你需要備份的文件。
2.調用addHelper去給備份代理輔助類添加輔助。
下文將會詳述如何使用每個可用的助手去創建備份代理。
當你實例化了SharedPreferencesBackupHelper類,你必須在其中包含一個或多個SharedPreferences文件的名稱。
例如,備份一個名為”user_preferences”的SharedPreferences文件,一個使用BackupAgentHelper的完整的備份代理如下:
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類幫助我們為你的文件進行備份和還原操作。
注意:SharedPreferences是線程安全的,所以你可以在你的備份代理和其他的Activity類裡安全地對其進行讀寫操作。
當你實例化了一個FileBackupHelper類,你必須在其中包含存儲到你的應用的內部存儲的文件名(由getFilesDir()函數所指定的,它與openFileOutput()函數寫文件的位置是相同的)。
例如,備份兩個名為“scores”和“stats”的文件,一個備份代理像下文那樣使用備份代理輔助類(BackupAgentHelper):
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包含了備份和還原你存儲到內存中的文件所有必要代碼。
但是,在內部存儲裡讀寫文件不是線程安全的。為了保證你的備份代理不與你的Activity同時讀寫文件,你必須使用synchronize代碼塊。例如,在任何一個Activity裡你讀寫這些文件的時候,你需要一個對象作為 synchronized代碼塊的內部鎖:
// 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");
}
你應該用同一個鎖去同步你的讀語句塊。
然後,在你的備份代理輔助類(BackupAgentHelper)裡,你必須重寫onBackup()和onRestore()方法去用同一個內部鎖去同步備份和還原操作。例如,這個上文提到的MyFileBackupAgent例子需要如下的方法:
@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);
}
}
就是這些了。所有你需要做的就是在onCreate()方法裡添加文件備份助手(FileBackupHelper)和重寫onBackup()和onRestore()方法去同步讀寫操作。
用文件備份助手實現的備份代理輔助的例子,詳見Backup and Restore 應用的FileHelperExampleAgent類。
當備份管理存儲你的數據到雲存儲的時候,它自動包含了你的應用的版本,也就是你的manifest文件裡的android:versionCode屬性的值。在備份管理調用的備份代理去還原你的數據之前,它會著眼於已經安裝的應用的android:versionCode屬性,並且把它與在還原數據set裡記錄的值進行比較。如果記錄在還原數據集合(set)裡的版本比應用裡的新,用戶的app等級較低。在這種情況下,備份管理將會為你的應用放棄還原操作並且不再調用onRestore()方法,因為對於舊版本來說,還原集合已經沒有意義了。
你可以用android:restoreAnyVersion這個屬性重寫這個行為。這個屬性是true或者false去表明你是否想去還原應用,不管之前的集合裡的版本比較。默認值是false。如果你把這個屬性定義為true的話,備份管理將會忽略android:versionCode並且無論怎樣都會調用你的onRestore()方法。通過這個操作,你可以在onRestore()方法裡手動檢查版本差異並且當版本沖突的時候,可以采取任何步驟去保證數據的完整。
為了幫助你的在還原過程中去處理不同的版本,onRestore()傳遞給你與還原數據一起的版本號作為appVersionCode參數。你可以用PackageInfo.versionCode 查詢現在應用的版本號。例如:
PackageInfo info;
try {
String name = getPackageName();
info = getPackageManager().getPackageInfo(name,0);
} catch (NameNotFoundException nnfe) {
info = null;
}
int version;
if (info != null) {
version = info.versionCode;
}
然後直接比較從PackageInfo中獲取的版本和onRestore()傳遞的參數appVersionCode。
注意:這裡確信你是否了解了設置android:restoreAnyVersion為false或者true的結果。如果每個支持備份的應用版本在onRestore()期間沒有正確考慮你的數據結構的變化,那麼設備上的數據有可能會以一個不完整的格式存儲(與現在設備上版本的數據不匹配)。
在你的應用的正常生命周期內,你應該不需要去請求一個數據還原操作。系統自動地去檢查備份數據並且當你的應用被安裝的時候去執行相應的還原操作。但是,在必要的情況下,你可以通過調用requestRestore()手動地請求還原操作。在這種情況下,備份管理調用你的onRestore()方法,傳遞備份數據集合中的數據。
注意:當你在開發你的應用時,你可以用bmgr tool請求還原操作。
一旦你實現了你的備份代理,你可以測試備份並且使用下面的步驟還原功能,使用bmgr:
1.在一個合適的Android系統鏡像上安裝你的應用。
(1)如果你使用模擬器,創建並使用一個2.2版本的模擬器(API 8)
(2)如果在使用真機,它的Android版本必須高於或等於2.2,並且上面要安裝了Google play。
2.保證備份功能是可用的。
(1)如果你使用的是模擬器,你可以通過 SDK tools/ path路徑的如下指令使備份有效:
adb shell bmgr enable true
(2)如果你使用的是真機,打開系統設置,選擇備份和重置( Backup & reset),然後打開備份我的數據(Back up my data)和自動還原(Automatic restore)。
3.打開你的應用並且初始化部分數據。
如果你在你的應用裡正確實現了備份,那麼每次當應用數據變更的時候,它都將請求備份操作。例如,每次用戶變更了數據,你的app將會調用dataChanged()函數,這個函數給你的備份管理隊列添加了一個備份請求。為了測試的目的,你可以通過bmgr 指令自己准備一個請求:
adb shell bmgr backup your.package.name
4.初始化備份操作:
adb shell bmgr run
這個操作讓備份管理去執行所有在他隊列裡的備份請求。
5.卸載你的應用:
adb uninstall your.package.name
6.重新安裝你的應用。
如果你的備份代理是成功的,所有你在步驟4裡初始化的數據將被還原。
上面這篇文章就是我的翻譯,這個備份功能應該是Google所自帶的,但是由於各種原因可能目前國內的開發者使用的都是自己的備份機制。由於個人興趣,我在這裡翻譯了這篇文章,英文水平不夠可能導致一些地方翻譯的不盡如人意,希望為我指出,謝謝~
忍耐和堅持雖是痛苦的事情,但卻能漸漸地為你帶來好處.——奧維德。可能在堅持一件事情一段時間後,我們腦海中會有很多放棄的念頭,可能在放棄之後的幾年後
1.打開百度雲,點擊窗口界面的右上方下拉菜單中的“設置”一項 2.你會看到許多實用的手機雲端備份功能,其中就有我們需要的短信備份
有兩種方式, 如果您取消綁定手機,豌豆莢便不會自動備份您的任何數據. 如果您選擇綁定手機,可以在「設置」-「自動備份」中取消選定「聯系人」「短信」的復選框, 這樣豌豆莢便
華為榮耀7手機這刷機的話如何去備份數據呢?這是很多人都關心的,這個問題想來困擾了很多的新手用戶,接下來就一起來看看