转载自:http://blog.csdn.net/y505772146/article/details/51291609
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里声明备份代理
这是最简单的一步,所以一旦你确认了你的备份代理类的名称,在Manifest文件的<application>标签里用android:backupAgent属性去声明它。
例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
另一个你可能会使用的属性是android:restoreAnyVersion。这个属性使用一个boolean值去表明你是否想去还原应用的数据,而不管产生备份数据的版本和当前版本的比较。(它的默认值是false)。请看检查还原数据的版本获取更多信息。
注意:因为你使用的备份服务和 API只有在API版本8(Android 2.2)或更高的时候是可用的,所以你必须同时设置你的android:minSdkVersion 属性为8。
注册Android备份服务
对于大部分2.2或以上的设备来说,Google提供了带Android Backup Service的备份传输。
为了使你的应用能够使用Android备份服务( Android Backup Service),你必须在你的应用里注册一个带 Backup Service 秘钥的service,并且在你的Manifest文件里声明这个秘钥。
为了获取你的备份服务秘钥,你需要注册Android备份服务。当你注册后,你会得到一个秘钥和一段 XML代码,你必须把它们用标签包含起来。例如:
- 1
- 2
- 3
- 4
- 5
- 6
android:name必须是”com.google.android.backup.api_key”,并且android:value必须是从Android备份服务注册得到的秘钥才可以。
如果你有多个应用,你必须使用各自的包名去注册每一个应用以便使用Android的备份服务。
注意:由android备份服务提供的备份传输并不是在所有Android设备上都是保证能使用的。有的设备使用另一种方式支持备份,有的设备完全不支持备份,并且你的应用不会知道你在当前设备上使用的是哪种传输。但是,如果你为你的应用实现了备份,你通常应该保留一个备份服务秘钥以便你的应用能够使用可用的Android备份传输服务。如果你的设备不能使用Android备份服务,”< meta-data >” 里的带秘钥的元素将会被自动忽视。
扩展备份代理(Extending BackupAgent)
大多数Android应用不需要直接扩展BackupAgent类,而是应该使用extend BackupAgentHelper 去使用可以自动备份和还原文件的内嵌类。但是,如果你需要如下的操作,你可能需要直接扩展BackupAgent类:
- 给你的数据设定版本。例如,如果你想你修复你写入应用数据的格式,在还原操作期间,你需要使用一个备份代理去反复检查你的应用版本。如果你设备上的应用版本与备份的版本是不同的,你需要做一些必要的兼容操作。请看检查还原数据版本去获取更多的信息。
- 与备份整个文件不同的是,你可以指定数据里哪一部分会被备份并且每个需要备份的部分是如何还原到设备上的。(这可以帮助你管理不同的版本,因为通过不同的特殊的标示去读写数据而不是整个文件)
- 在数据库里备份数据。如果当用户重新安装了你的App的时候,你有SQLite数据库数据需要还原,你需要一个自定义的备份代理去读取数据,并且创建你的表,把数据插入进去。
如果你不需要进行以上的操作并且需要从SharedPreferences和内部存储去备份完整的文件,你应该跳到扩展BackupAgentHelper类。
所需的方法
当你使用扩展BackupAgent类去备份数据,你必须实现如下的回调函数:
onBackup():
在你请求备份之后,备份管理调用了这个方法。在这个方法里,你从设备上读取应用数据并且把你想备份的数据传给Android备份管理,像下文操作备份那样描述的那样。
onRestore():
在还原期间,Android备份管理调用这个方法。(你可以自己请求还原操作,但是当用户重新安装了你的应用时,系统将自动进行备份数据的还原操作。)当这个方法被调用的时候,备份管理将会传递给应用备份数据,就像下文进行还原描述的那样。
进行备份(Performing backup)
当你正在备份你的应用数据时,备份管理调用了你的onBackup方法。你需要在这里提供你的应用数据给备份管理器以便你的数据能够存储到云存储上去。
只有Android的备份管理可以调用你的onBackup方法。每次当你的应用数据变更并且你想进行备份的时候,你必须调用dataChanged()去请求备份操作。(看请求备份去获取更多信息)一个备份请求不会立刻调用你的onBackup()方法。相反地,备份管理将会等待一个合适的时间,然后为所有的请求数据备份的应用进行备份。
提示:当开发你的应用的时候,你可以使用bmgr tool去发起一个即刻的来自备份管理的备份操作。
当备份管理调用了你的onBackup()方法,它传递了三个参数:
- 1
-
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)。最简单的去记录文件状态的方式是使用它最近一次变更的时间戳。例如下面:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
如果没有数据变更,你没必要进行备份,直接跳到第三步。
2.如果你的数据变更了,把你的数据写到 data 参数里,并且把它备份到云存储上。
你必须把每一块数据作为一个实体写在BackupDataOutput里。每个实体都是平整的二进制数据记录,并且每个都对应一个独一无二的字符串。因此,你缓存的数据在概念上可以理解为key-value类型存储的数据。
为了在你的备份数据集合里添加一个实体,你必须:
1.调用writeEntityHeader(),根据你要备份的数据和它的大小来传递一个特殊的字符串。
2.调用writeEntityData(),传递了一个字节缓冲区,它包含了你的数据和从缓冲区里需要写入的字节数(在这里应该和传递给writeEntityHeader()的大小匹配)。
例如,如下的代码把一些数据转换成了字节流,并且把它们写到了一个单独的实体里:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
对你的每一块你想备份的数据使用这段代码。如何分配你的数据到不同的实体里取决于你自己(有可能你只需要一个实体)。
3.无论你是否执行了备份(步骤2),向参数newState ParcelFileDescriptor写入当前数据的一个标示。备份管理本地保留了这个对象作为备份数据的标识。当下次调用onBackup()时,这个对象最为oldState参数传递以便你决定是否备份是必要的(像步骤1处理的那样)。如果你不写入当前的数据状态,oldState参数将会在下次回调是空值。
下面的例子存储了一个使用文件最后一次修改的时间戳的当前数据的标识到newState:
- 1
- 2
- 3
- 4
- 5
注意:如果你的应用数据被存储到一个文件里,当你访问文件的时候,确保你使用的是同步代码块以便你的备份代理不会在你的应用里的Activity修改这个文件的时候去读取它。
进行还原
当你想还原你的应用数据时,备份管理调用你的备份代理的onRestore()方法。当它调用这个方法时,备份管理将会传递你的数据以便你可以在设备上还原备份数据。
只有Android备份管理可以调用onRestore()方法,当系统在安装你的应用和找到存在的备份数据时将会被自动调用。但是,你可以通过调用requestRestore()去为你的应用手动请求数据还原操作。
注意:在开发你的应用的过程中,你也可以通过bmgr tool去进行还原操作的请求。
当备份管理调用你的onRestore()方法的时候,它传递了三个参数:
- 1
-
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()做的一样。
例如,下文是如何还原在上文的例子里备份的数据:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
在这个例子里,传递给onRestore()的appVersionCode参数没有被使用。但是,如果你在用户的应用版本落后的时候选择去备份的话,你有可能将去使用onRestore()函数(例如,用户从1.5版本到1.0版本)。去查看检查还原数据版本以获取更多的信息。
关于备份代理的例子,详见备份还原实例应用的ExampleAgent类。
扩展的备份代理辅助类(Extending BackupAgentHelper)
如果你想备份完整的文件,你应该使用备份代理辅助类去创建备份代理(不管是SharedPreferences还是内部存储)。用备份代理辅助类创建自己的备份代理需要的代码远远少于扩展代理,因为你不需要实现onBackup()和onRestore()方法。
你的备份代理辅助类的实现必须使用一个或多个备份助手。备份助手是一个专门的组件,备份辅助类召集备份助手去进行备份和为特定类型的数据进行还原操作。Android框架目前提供了两个助手:
- SharedPreferencesBackupHelper :备份SharedPreferences文件。
- FileBackupHelper:备份内存中的文件。
你可以在你的备份辅助类中包含多个上文所示的助手,你必须在onCreate()的时候做下面的操作:
1.给需要的辅助类生成一个实例。在类的构造函数里,你必须要指定你需要备份的文件。
2.调用addHelper去给备份代理辅助类添加辅助。
下文将会详述如何使用每个可用的助手去创建备份代理。
备份SharedPreferences
当你实例化了SharedPreferencesBackupHelper类,你必须在其中包含一个或多个SharedPreferences文件的名称。
例如,备份一个名为”user_preferences”的SharedPreferences文件,一个使用BackupAgentHelper的完整的备份代理如下:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
就是这样!这是你完整的备份代理。SharedPreferencesBackupHelper类包含了还原和备份所有SharedPreferences文件的代码。
当备份管理调用了onBackup()和onRestore方法的时候,BackupAgentHelper类帮助我们为你的文件进行备份和还原操作。
注意:SharedPreferences是线程安全的,所以你可以在你的备份代理和其他的Activity类里安全地对其进行读写操作。
备份其它文件
当你实例化了一个FileBackupHelper类,你必须在其中包含存储到你的应用的内部存储的文件名(由getFilesDir()函数所指定的,它与openFileOutput()函数写文件的位置是相同的)。
例如,备份两个名为“scores”和“stats”的文件,一个备份代理像下文那样使用备份代理辅助类(BackupAgentHelper):
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
FileBackupHelper包含了备份和还原你存储到内存中的文件所有必要代码。
但是,在内部存储里读写文件不是线程安全的。为了保证你的备份代理不与你的Activity同时读写文件,你必须使用synchronize代码块。例如,在任何一个Activity里你读写这些文件的时候,你需要一个对象作为 synchronized代码块的内部锁:
- 1
- 2
然后在每次你读写这些文件的时候,用这个对象锁去创建同步代码块。例如,这里有一个同步代码块去写一场比赛的最新分数到一个文件里:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
你应该用同一个锁去同步你的读语句块。
然后,在你的备份代理辅助类(BackupAgentHelper)里,你必须重写onBackup()和onRestore()方法去用同一个内部锁去同步备份和还原操作。例如,这个上文提到的MyFileBackupAgent例子需要如下的方法:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
就是这些了。所有你需要做的就是在onCreate()方法里添加文件备份助手(FileBackupHelper)和重写onBackup()和onRestore()方法去同步读写操作。
用文件备份助手实现的备份代理辅助的例子,详见Backup and Restore 应用的FileHelperExampleAgent类。
检查还原数据版本(Checking the Restore Data Version)
当备份管理存储你的数据到云存储的时候,它自动包含了你的应用的版本,也就是你的manifest文件里的android:versionCode属性的值。在备份管理调用的备份代理去还原你的数据之前,它会着眼于已经安装的应用的android:versionCode属性,并且把它与在还原数据set里记录的值进行比较。如果记录在还原数据集合(set)里的版本比应用里的新,用户的app等级较低。在这种情况下,备份管理将会为你的应用放弃还原操作并且不再调用onRestore()方法,因为对于旧版本来说,还原集合已经没有意义了。
你可以用android:restoreAnyVersion这个属性重写这个行为。这个属性是true或者false去表明你是否想去还原应用,不管之前的集合里的版本比较。默认值是false。如果你把这个属性定义为true的话,备份管理将会忽略android:versionCode并且无论怎样都会调用你的onRestore()方法。通过这个操作,你可以在onRestore()方法里手动检查版本差异并且当版本冲突的时候,可以采取任何步骤去保证数据的完整。
为了帮助你的在还原过程中去处理不同的版本,onRestore()传递给你与还原数据一起的版本号作为appVersionCode参数。你可以用PackageInfo.versionCode 查询现在应用的版本号。例如:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
然后直接比较从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路径的如下指令使备份有效:
- 1
(2)如果你使用的是真机,打开系统设置,选择备份和重置( Backup & reset),然后打开备份我的数据(Back up my data)和自动还原(Automatic restore)。
3.打开你的应用并且初始化部分数据。
如果你在你的应用里正确实现了备份,那么每次当应用数据变更的时候,它都将请求备份操作。例如,每次用户变更了数据,你的app将会调用dataChanged()函数,这个函数给你的备份管理队列添加了一个备份请求。为了测试的目的,你可以通过bmgr 指令自己准备一个请求:
- 1
4.初始化备份操作:
- 1
这个操作让备份管理去执行所有在他队列里的备份请求。
5.卸载你的应用:
- 1
6.重新安装你的应用。
如果你的备份代理是成功的,所有你在步骤4里初始化的数据将被还原。
上面这篇文章就是我的翻译,这个备份功能应该是Google所自带的,但是由于各种原因可能目前国内的开发者使用的都是自己的备份机制。由于个人兴趣,我在这里翻译了这篇文章,英文水平不够可能导致一些地方翻译的不尽如人意,希望为我指出,谢谢~