- android
- android.accessibilityservice
- android.accounts
- android.content
- android.database.sqlite
- android.graphics
- android.location
- android.media
- android.net
- android.os
- android.text
- android.view
- android.view.inputmethod
- android.widget
- AbsListView
- AbsoluteLayout
- AbsSeekBar
- AbsSpinner
- AdapterView
- AnalogClock
- BaseAdapter
- BaseExpandableListAdapter
- Button
- CheckBox
- CheckedTextView
- Checkable
- Chronometer
- CompoundButton
- CursorAdapter
- CursorTreeAdapter
- DatePicker
- DialerFilter
- DigitalClock
- EditText
- Filter
- Filter.FilterListener
- Filter.FilterResults
- ExpandableListAdapter
- Filterable
- Gallery
- Gallery.LayoutParams
- GridView
- GridLayout
- RadioGroup
- ImageView
- HorizontalScrollView
- ImageButton
- ImageSwitcher
- FilterQueryProvider
- ListAdapter
- ListView
- MediaController
- QuickContactBadge
- RadioButton
- RatingBar
- RelativeLayout
- RemoteViews
- ResourceCursorAdapter
- ResourceCursorTreeAdapter
- Scroller
- ScrollView
- SearchView
- SeekBar
- SeekBar.OnSeekBarChangeListener
- SimpleAdapter
- SimpleCursorAdapter
- SimpleCursorTreeAdapter
- SimpleExpandableListAdapter
- SlidingDrawer
- Spinner
- SpinnerAdapter
- WrapperListAdapter
- TabHost
- TabHost.TabSpec
- TextView
- TimePicker
- Toast
- TableLayout
- TableRow
- TableRow.LayoutParams
- TabWidget
- TextSwitcher
- ToggleButton
- TwoLineListItem
- VideoView
- ViewAnimator
- ViewFlipper
- ViewSwitcher
- ZoomButtonsController
- ZoomButton
- ZoomControls
- dalvik.system
数据备份
数据备份
译者微博: http://weibo.com/popapa
版本:Android 4.0 r1
原文
http://developer.android.com/guide/topics/data/backup.html
快速查看
· 将用户数据备份到云中心以防丢失。
· 如果用户升级到运行 Android 的新设备,程序可以恢复用户数据到新设备中。
· 可方便地用 BackupAgentHelper 备份 SharedPreference 和私有文件。
· 需要 API Level 8 支持。
在本文中
关键类
参阅
为了给应用程序的数据和配置信息提供数据还原点,Android 的备份 backup 服务允许把需持久保存的数据拷贝到远程“云”存储中。如果用户恢复了出厂设置或者换用新的 Android 设备,系统将在再次安装应用程序时自动恢复备份数据。这样,就不需要用户复制之前的数据和程序配置信息。整个过程对于用户而言完全透明,不会影响程序的功能和用户体验度。
在备份过程中(应用程序可发起请求),Android 的备份管理器( BackupManager )将查找应用程序中需备份的数据,并把数据交给备份传输器,传输器再把数据传送给云存储。在恢复时,备份管理器从备份传输器取回备份数据并将其返回给应用程序,然后应用程序就能把数据恢复到设备上。应用程序也能够发起恢复请求,但不是必须的——如果程序安装完毕且存在用户相关的备份数据,Android 会自动执行恢复操作。恢复备份数据主要发生于以下场合:用户重置设备或者升级到新设备后,以前装过的应用程序又被再次安装。
注意: 备份服务并 不是 为以下用途设计的:与其它客户端同步、在程序正常生命周期内保存数据。备份数据不允许随意读写,除通过备份管理器提供的 API 外无法访问数据。
备份传输器是 Android 备份框架的客户端组件,它可由设备制造商和提供商定制。备份传输器可以因设备不同而不同,对于应用程序而言它是透明的。备份管理器的 API 将应用程序和实际备份传输器联接起来——程序通过一组固定的 API 与备份管理器进行通讯,而不必关心底层的传输过程。
并 不是 所有 Android 平台的设备都能支持数据备份。不过,即使设备不支持备份传输,对程序运行也不会有什么影响。如果确信用户将受益于数据备份服务,只管按照本文所述去实现、测试并发布即可,而不必去关心哪些设备会真正执行备份工作。就算是在不支持备份传输的设备上,程序仍然会正常运行,只是不能接收备份管理器的请求进行数据备份而已。
尽管对当前所传输内容一无所知,但尽管放心,备份数据是不能被设备上的其它程序读取的。在备份过程中,只有备份管理器和备份传输器有权限访问被提交的数据。
警告: 因为云存储和传输服务依设备而各不相同,Android 不保证使用备份服务数据的安全性。如果要利用备份服务保存敏感数据(比如用户名和密码),应该始终保持谨慎态度。
为了备份应用程序数据,需要实现一个备份代理。此备份代理将被备份管理器调用,用于提供所需备份的数据。当程序重装时,还要调用此代理来恢复数据。备份管理器处理所有与云存储之间的数据传输工作(利用备份传输器),备份代理则负责所有对设备上数据的处理。
要实现备份代理,必须:
1. 在 manifest 文件内用 android:backupAgent 属性声明备份代理。
2. 用备份服务对应用程序进行注册。Google 为大多数 Android 平台的设备提供了 Android 备份服务 ,必须对应用程序进行注册以便服务生效。为了在它们的服务器上存储数据,其它所有的备份服务提供方也都可能需要注册。
3. 用以下两种方式之一进行备份代理的定义:
BackupAgent 类提供了核心接口,程序通过这些接口与备份管理器进行通讯。如果直接继承此类,必须覆盖 onBackup() 和 onRestore() 方法来处理数据的备份和恢复操作。
BackupAgentHelper 类提供了 BackupAgent 类的易用性封装,它减少了需编写的代码数量。在 BackupAgentHelper 内,必须用一个或多个“helper”对象来自动备份和恢复特定类型的数据,因此不再需要实现 onBackup() 和 onRestore() 方法了。
Android 目前提供两种 backup helper,用于从 SharedPreferences 和 internal storage 备份和恢复整个的文件。
在 Manifest 中声明备份代理
这是最容易的一步,一旦确定了类名,就可在 manifest 的 <application> 标签内用 android:backupAgent 属性声明备份代理了。
例如:
<manifest ... >
...
<application android:label="MyApplication"
android:backupAgent = "MyBackupAgent" >
<activity ... >
...
</activity>
</application>
</manifest>
其它可能会用到的属性是 android:restoreAnyVersion 。这个属性用布尔值标明恢复数据时是否忽略当前程序和产生备份数据的程序之间的版本差异(默认值是“false”)。详情请参阅 检查恢复数据的版本 。
注意: 备份服务和 API 只在运行 API Level 8(Android 2.2)以上版本的设备上才可用,因此应把 android:minSdkVersion 属性设为“8”。当然,如果程序实现了良好的 向后兼容性 ,可以仅针对 API Level 8 以上版本的设备提供备份功能,而对其它旧版本设备则保持兼容即可。
为 Android 备份服务进行注册
Google 为大多数 Android 2.2 以上版本的设备提供了利用 Android 备份服务 进行的备份传输服务。
为了程序能利用 Android 备份服务执行备份操作,必须对程序进行注册以获得一个 Backup Service Key,然后在 Android manifest 文件中声明这个 Key。
要获取 Backup Service Key,请 为 Android 服务进行注册 。注册时会得到一个 Backup Service Key 和 Android manifest 文件内相应的<meta-data> XML 代码,这段代码必须包含在<application> 元素下。例如:
<application android:label="MyApplication"
android:backupAgent="MyBackupAgent">
...
<meta-data android:name="com.google.android.backup.api_key"
android:value="AEdPqrEAAAAIDaYEVgU6DJnyJdBmU7KLH3kszDXLv_4DIsEIyQ" />
</application>
android:name 必须是"com.google.android.backup.api_key" ,android:value 也必须是注册 Android 备份服务时收到的 Backup Service Key。
如果存在多个应用程序,必须根据各自的程序包名称(package name)为每一个程序进行注册。
注意: 即使设备能够支持,Android 备份服务提供的备份传输器也不一定在所有 Android 平台的设备上都能执行。有些设备可能使用不同的传输器来为备份提供支持,有些设备可能根本就不支持备份,程序是无法知道设备使用何种传输器的。不过,假如为程序实现了备份,就必须为备份服务指定 Backup Service Key,这样设备利用 Android 备份服务进行传输时程序就能顺利执行备份工作。如果设备不使用 Android 备份服务,带 Backup Service Key 的<meta-data>元素将被忽略。
继承 BackupAgent
大多数应用程序应该不需要直接继承使用 BackupAgent 类,取而代之的是 继承 BackupAgentHelper 类,并利用 BackupAgentHelper 内建的 helper 类自动备份和恢复文件。不过,如果需要实现以下目标的话,也许希望能直接继承 BackupAgent :
· 将数据格式版本化。例如需要在恢复数据时修正格式,可以建立一个备份代理,在数据恢复过程中如果发现当前版本和备份时的版本不一致,可以执行必要的兼容性修正工作。详情请参阅 检查恢复数据的版本 。
· 不是备份整个文件,而是指定备份部分数据及指定恢复各部分数据。(这也有助于管理不同版本的数据,因为是把数据作为唯一 Entity 来读写,而不是读写整个文件。)
· 备份数据库中的数据。如果用到 SQLite 数据库并且希望用户重装系统时能恢复其中数据,需要建立自定义的 BackupAgent 。它在备份时读取库中数据,而在恢复时建表并插入数据。
如果不需要执行以上的任务,而只是从 SharedPreferences 或 内部存储 备份完整的文件,请跳转到 继承 BackupAgentHelper 。
通过继承 BackupAgent 创建备份代理时,必须实现以下回调方法:
备份管理器在程序 请求备份 后将调用本方法。如下文 执行备份 所述,在本方法中实现从设备读取应用程序数据,并把需备份的数据传递给备份管理器。
备份管理器在恢复数据时调用本方法(也可以主动 请求恢复 ,但在用户重装应用程序时系统会自动执行数据恢复。)如下文 执行恢复 所述,备份管理器调用本方法时将传入备份的数据,然后就可把数据恢复到设备上。
执行备份
备份应用程序数据时,备份管理器将调用 onBackup() 方法。在此方法内必须把数据提供给备份管理器,然后数据被保存到云存储中。
只有备份管理器能够调用备份代理中的 onBackup() 方法。每当数据发生改变并需要执行备份时,必须调用 dataChanged() 发起一次备份请求(详情请参阅 请求备份 )。备份请求并不会立即导致 onBackup() 方法的调用。备份服务器会等待合适的时机,为上次备份操作后又发出备份请求的所有应用程序执行备份。
提示: 在开发应用程序的过程中,可以用 bmgr 工具 让备份管理器立即执行备份操作。
当备份管理器调用 onBackup() 方法时,传入以下三个参数:
oldState
已打开的、只读的文件描述符 ParcelFileDescriptor ,指向应用程序提供的有关上次备份数据状态的文件。这不是来自云存储的备份数据,而是记录上次调用 onBackup() 所备份数据相关状态信息的本地文件(如下文 newState 所定义,或来自下节 onRestore() )。因为 onBackup() 不允许读取保存于云存储的数据,可以根据此信息来判断数据自上次备份以来是否变动过。
data
BackupDataOutput 对象,用于将备份数据传给备份管理器。
newState
已打开的、可读写的文件描述符 ParcelFileDescriptor ,指向一个文件,必须将提交给 data 参数的数据相关状态信息写入此文件(此状态信息可以简单到只是文件的最后修改时间戳)。备份管理器下次调用 onBackup() 时,本对象作为 oldState 传入。如果没有往 newState 写入信息,则备份管理器下次调用 onBackup() 时 oldState 将指向一个空文件。
利用以上参数,可以实现 onBackup() 方法如下:
1. 通过比较 oldState,检查自上次备份以来数据是否发生改变。从 oldState 读取信息的方式取决于当时写入的方式(见第 3 步)。最简单的记录文件状态的方式是写入文件的最后修改时间戳。以下是如何从 oldState 读取并比较时间戳的例子:
// 获取 oldState 输入流
FileInputStream instream = new FileInputStream(oldState.getFileDescriptor());
DataInputStream in = new DataInputStream(instream);
try {
// 从 state 文件和数据文件获取最后修改时间戳
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
}
如果数据没有发生变化,就不需要进行备份,请跳转到第 3 步。
2. 在和 oldState 比较后,如果数据发生了变化,则把当前数据写入 data 以便将其返回并上传到云存储中去。
必须以 BackupDataOutput 中的“entity”方式写入每一块数据。一个 entity 是用一个唯一字符串键值标识的拼接二进制数据记录。因此,所备份的数据集其实上是一组键值对。
要在备份数据集中增加一个 entity,必须:
1. 调用 writeEntityHeader() ,传入代表写入数据的唯一字符串键值和数据大小。
2. 调用 writeEntityData() ,传入存放数据的字节类型缓冲区,以及需从缓冲区写入的字节数(必须与传给 writeEntityHeader() 的数据大小一致)。
例如,以下代码把一些数据拼接为字节流并写入一个 entity:
// 为数据创建缓冲区流和输出流
ByteArrayOutputStream bufStream = new ByteArrayOutputStream();
DataOutputStream outWriter = new DataOutputStream(bufStream);
// 写入结构化的数据
outWriter.writeUTF(mPlayerName);
outWriter.writeInt(mPlayerScore);
// 通过 BackupDataOutput 发送数据到备份管理器 Backup Manager
byte[] buffer = bufStream.toByteArray();
int len = buffer.length;
data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);
data.writeEntityData(buffer, len);
对每一块需备份的数据都要执行以上操作。程序负责把数据切分为多个 entity(当然也可以只用一个 entity)。
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);
警告: 如果应用程序数据存放于文件中,请确保使用同步语句(synchronized)来访问文件。这样在应用程序的 Activity 写文件时,备份代理就不会去读文件了。
执行恢复
恢复程序数据时,备份管理器将调用备份代理的 onRestore() 方法。调用此方法时,备份管理器会把备份的数据传入,以供恢复到设备中去。
只有备份服务器能够调用 onRestore() ,在系统安装应用程序并且发现有备份数据存在时,调用会自动发生。不过,也可以通过调用 requestRestore() 来发起恢复数据的请求(详情参阅 请求恢复 )。
注 : 在开发应用程序的过程中,可以用 bmgr 工具 发起恢复数据的请求。
当备份管理器调用 onRestore() 方法时,传入以下三个参数:
data
BackupDataInput 对象,用以读取备份数据。
appVersionCode
整数,表示备份数据时应用程序 manifest 中的 android:versionCode 属性。可以用于核对当前程序版本并确定数据格式的兼容性。关于利用此版本号来处理不同版本恢复数据的详细情况,请参阅下文检查恢复数据的版本 。
newState
已打开的,可读写的文件描述符 ParcelFileDescriptor ,指向一个文件,这里必须写入最后一次提交 data 数据的备份状态。本对象在下次调用 onBackup() 时作为 oldState 返回。回想一下, onBackup() 方法也必须写入 newState 对象——这里也同样要这么做。这样即使设备重置后第一次调用 onBackup() ,也能确保有可用的 oldState 对象能传给 onBackup() 方法。
在实现 onRestore() 时,应该对 data 调用 readNextHeader() ,以遍历数据集里所有的 entity。对其中每个 entity 须进行以下操作:
1. 用 getKey() 获取 entity 的键值。
2. 将此 entity 键值和已知键值清单进行比较,这个清单应该已经在 BackupAgent 继承类中作为字符串常量(static final string)进行定义。一旦键值匹配其中一个键,就执行读取 entity 数据并保存到设备的语句:
1. 用 getDataSize() 读取 entity 数据大小并据其创建字节数组。
2. 调用 readEntityData() ,传入字节数组作为获取数据的缓冲区,并指定起始位置和读取字节数。
3. 字节数组将被填入数据,按需读取数据并写入设备即可。
3. 把数据读出并写回设备以后,和上面 onBackup() 过程类似,把数据的状态写入 newState 参数。
下面是把前一节例子中所备份的数据进行恢复的示例:
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
ParcelFileDescriptor newState) throws IOException {
// 应该是只有一个 entity,
// 但最安全的方法还是用循环来处理
while (data.readNextHeader()) {
String key = data.getKey();
int dataSize = data.getDataSize();
// 如果键值是所需的(保存 Top Score),注意这个键值是用于
// 写入备份 entity header
if (TOPSCORE_BACKUP_KEY.equals(key)) {
// 为 BackupDataInput 创建输入流
byte[] dataBuf = new byte[dataSize];
data.readEntityData(dataBuf, 0, dataSize);
ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);
DataInputStream in = new DataInputStream(baStream);
// 从备份数据中读取 player name 和 score
mPlayerName = in.readUTF();
mPlayerScore = in.readInt();
// Record the score on the device (to a file or something)
recordScore(mPlayerName, mPlayerScore);
} else {
// 不知道这个 entity 键值,跳过,(这本不该发生)
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 参数没有被用到。假如用户程序的版本已经降级(比如从 1.5 降到 1.0),可能就会用此参数来选择备份数据。更多信息请参阅 检查恢复数据的版本 。
关于 BackupAgent 的完整例子,请参阅例程 备份和恢复 中的 ExampleAgent 类。
如果要备份整个文件(来自 SharedPreferences 或 内部存储 ),应该用 BackupAgentHelper 创建备份代理来实现。因为不必实现 onBackup() 和 onRestore() 了, 用 BackupAgentHelper 创建备份代理所需的代码量将远远少于 BackupAgent 。
BackupAgentHelper 的实现必须要使用一个或多个 backup helper。backup helper 是一种专用组件, BackupAgentHelper 用它来对特定类型的数据执行备份和恢复操作。Android 框架目前提供两种 helpers:
· SharedPreferencesBackupHelper 用于备份 SharedPreferences 文件。
· FileBackupHelper 用于备份来自 内部存储 的文件。
在 BackupAgentHelper 中可包含多个 helper,但对于每种数据类型只需用到一个 helper 。也就是说,即使存在多个 SharedPreferences 文件,也只需要一个 SharedPreferencesBackupHelper 。
对于每个要加入 BackupAgentHelper 的 helper,必须在 onCreate() 中执行以下步骤:
1. 实例化所需的 helper。在其构造方法里必须指定需备份的文件。
2. 调用 addHelper() 把 helper 加入 BackupAgentHelper 。
下一节描述了如何使用每种 helper 创建备份代理。
实例化 SharedPreferencesBackupHelper 时,必须包括一个或多个 SharedPreferences 文件。
例如,假设需备份的 SharedPreferences 文件名为“user_preferences”,完整的使用 BackupAgentHelper 的备份代理代码类似如下:
public class MyPrefsBackupAgent extends BackupAgentHelper {
// SharedPreferences 文件名
static final String PREFS = "user_preferences";
// 唯一标识备份数据的键值
static final String PREFS_BACKUP_KEY = "prefs";
// 申请 helper 并加入备份代理
@Override
public void onCreate() {
SharedPreferencesBackupHelper helper = new SharedPreferencesBackupHelper(this, PREFS);
addHelper(PREFS_BACKUP_KEY, helper);
}
}
好,这就是一个备份代理的完整实现。 SharedPreferencesBackupHelper 内含了备份和恢复 SharedPreferences 文件的所有代码。
当备份管理器调用 onBackup() 和 onRestore() 时, BackupAgentHelper 调用 helper 来对给定文件执行备份和恢复操作。
注: SharedPreferences 是线程安全的,因此可以从备份代理和其它 activity 中安全地读写 shared preferences 文件。
在实例化 FileBackupHelper 时,必须包含一个或多个保存于程序 内部存储 中的文件名称。(路径的描述方式类似 getFilesDir() ,并且作为 openFileOutput() 写入文件的路径。)
比如,需要备份两个名为“scores”和“stats”的文件,备份代理使用 BackupAgentHelper 示例如下:
public class MyFileBackupAgent extends BackupAgentHelper {
// SharedPreferences 文件的名称
static final String TOP_SCORES = "scores";
static final String PLAYER_STATS = "stats";
// 唯一标识备份数据集的键值
static final String FILES_BACKUP_KEY = "myfiles";
// 申请 helper 并加入备份代理
void onCreate() {
FileBackupHelper helper = new FileBackupHelper(this, TOP_SCORES, PLAYER_STATS);
addHelper(FILES_BACKUP_KEY, helper);
}
}
FileBackupHelper 包含了备份和恢复存于 内部存储 的文件所需的全部代码。
但是,读写内部存储文件 不是线程安全 的。要确保 activity 操作文件的时候备份代理不会去读写文件,每次读写文件时必须使用同步语句。比如,Activity 读写文件时,需要用一个对象作为同步语句的内部锁。
// 内部锁对象
static final Object[] sDataLock = new Object[0];
有趣的事实: 长度为零的数组要比普通对象更轻量化,因此用作内部锁会是个好主意。
然后,每次读写文件时用这个锁创建同步语句。以下是把游戏分数写入文件的同步语句示例:
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() 并同步读写。
关于用 FileBackupHelper 实现 BackupAgentHelper 的例子,请参阅例程 备份和恢复 中的 FileHelperExampleAgent 类。
在把数据保存到云存储中去时,备份管理器会自动包含应用程序的版本号,版本号是在 manifest 文件的 android:versionCode 属性中定义的。在调用备份代理恢复数据之前,备份管理器会查询已安装程序的 android:versionCode ,并与记录在备份数据中的版本号相比较。如果备份数据的版本比设备上的要 新 ,则意味着用户安装了旧版本的程序。这时备份管理器将停止恢复操作, 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 中的 version 和传入 onRestore() 的 appVersionCode 即可。
警告: 请确认已经理解了 android:restoreAnyVersion 设为“true”的后果。如果不是所有版本的程序都能在 onRestore() 时正确解析数据格式的差异,那么保存到设备上的数据格式可能会与已安装的版本不兼容。
任何时候都可以通过调用 dataChanged() 来发起备份请求。此方法通知备份管理器用备份代理来备份数据。然后,备份管理器将会适时调用备份代理的 onBackup() 方法。通常每次数据发生变化时都应该请求备份数据(比如用户修改了需保存的程序配置)。如果在备份管理器实际执行前连续调用了 dataChanged() 很多次,代理仅会执行一次 onBackup() 。
注: 在程序开发过程中,可以用 bmgr tool 发起备份请求,备份将会立即执行。
在程序正常的生命周期内,应该不需要发起恢复数据的请求。在程序安装完成时,系统会自动检查备份数据并执行恢复操作。不过必要时,也可以通过调用 requestRestore() 来人工发起恢复数据的请求。这时,备份管理器会调用 onRestore() ,并把现有备份数据集作为数据传入该方法。
注: 在程序开发过程中,可以用 bmgr tool 发起恢复数据的请求。
一旦实现了备份代理,就可以用 bmgr 按以下步骤测试备份和恢复功能了:
1. 在合适的 Android 系统镜像上安装应用程序
o 如果使用仿真器,须创建和使用 Android 2.2(API Level 8)以上版本的 AVD。
o 如果使用硬件设备,则此设备必须运行 Android 2.2 以上版本并内置 Android Market 功能。
2. 确保启用备份功能
o 如果使用仿真器,可以在 SDK tools/路径下用以下命令启用备份功能:
adb shell bmgr enable true
o 如果使用硬件设备,则在系统 Settings , 选择 Privacy ,启用 Back up my data 和 Automatic restore 。
3. 运行程序并初始化一些数据。
如果程序已经正确地实现了备份代码,那每次数据变化时都会请求备份。例如,每当用户改变了一些数据,程序将调用 dataChanged() ,这就往备份管理器的请求队列里加入了一个备份请求。出于测试的目的,也可以用以下 bmgr 命令发起一个请求:
adb shell bmgr backup your.package.name
4. 执行备份操作:
adb shell bmgr run
这一步强迫备份管理器执行所有已入队列的备份请求。
5. 卸载应用程序:
adb uninstall your.package.name
6. 重新安装应用程序。
如果备份代理成功运行,那第 4 步里备份的数据将会被恢复。
补充
文章精选
[IBM] 基于 android 数据备份恢复的一种实现
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论