数据备份概述:
Android的backup服务让我们可以复制自己的持久化数据到远程”云”存储, 可以为APP数据和设置提供一个还原点. 如果用户执行了恢复出厂设置或者转移到了一个新的Android设备, 系统会在APP重新安装的时候自动还原之前备份的数据. 通过这种方式, 我们的用户不需要复制它们之前的数据或者APP设置. 这个流程对用户完全透明而不会影响到APP的功能或者用户体验.
在一个备份操作中, Android的备份管理器(BackupManager)查询我们的APP中的备份数据, 然后告知一个备份运输组件, 这东西将会把数据传递给云存储. 在恢复备份的操作中, Backup Manager从备份运输组件取回备份数据并将它交还给APP, 这样APP就可以恢复数据到设备了. 我们的APP可以自己主动选择恢复, 但是通常这是不必要的, 因为Android会在APP安装的时候自动执行一个恢复操作(前提是要有相关联的备份). 所以第一选择应该是当用户重置设备或者更新到一个新的设备并且他们之前安装的APP被重新安装的时候(自动恢复).
注意: 备份服务不是设计用来为APP跟其它客户端同步数据或者保存在普通生命周期中访问普通数据的. 我们不能在需要的时候去读写这些数据也不能通过Backup Manager提供的API用任何方式访问它们.
备份运输是Android的backup framework的客户端组件, 它是由设备生产厂家自定义的service provider. 备份运输在不同设备间可能会有所差异, 设备提供了怎样的备份运输对于我们的APP是透明的. Backup Manager API是APP和真正的备份运输之间的适配层, 这样我们的APP只需要跟Backup Manager通信就可以了, 而不用理会底层的实现.
数据备份并不保证在所有的Android设备上可用. 但是我们的APP不会因为设备不提供一个备份运输就产生不利影响. 如果开发的时候确信用户会从数据备份中受益, 那么可以使用该文档中描述的来实现它, 测试它, 然后发布APP而不关心设备如何执行备份. 当APP运行在一个不支持备份运输的设备上时, 我们的APP会正常运行, 但是将不会收到从Backup Manager发出的回调.
尽管我们不知道当前的备份运输是什么, 但是我们的备份数据总是可以保证不被其它的APP访问到. 只有Backup Manager和备份运输拥有访问备份数据的权限.
注意: 因为云存储和运输服务在设备间可能会有所差异, Android不保证使用数据备份的时候的加密问题. 我们应该总是自己谨慎对待使用备份来保存敏感信息, 比如用户名和密码.
数据备份基础:
想要备份我们的APP数据, 需要先实现一个备份代理. 备份代理被Backup Manager调用来提供我们想要备份的数据. 它也会在数据恢复的时候调用. Backup Manager处理云存储中所有的数据交换(使用备份运输), 备份代理则处理所有的设备上的数据交换. 要实现一个备份代理, 我们必须:
1. 在manifest中用android:backupAgent属性声明我们的备份代理.
2. 注册APP到一个备份服务. Google提供了Android Backup Service作为大多数的Android设备的备份服务. 它要求我们在使用之前先注册APP. 任何其它可用备份服务一般也需要先注册服务, 然后才能提供服务.
3. 通过下面的两种方式之一定义一个备份代理:
a) 继承BackupAgent: BackupAgent类提供了APP与BackupManager通信的核心接口. 如果我们直接继承了该类, 则必须重写onBackup()和onRestore()方法来处理数据的备份和恢复操作.
b) 继承BackupAgentHelper: BackupAgentHelper类提供了对BackupAgent的封装, 使其用法更加的便捷, 它最小化了我们需要实现的代码. 在我们的BackupAgentHelper中, 必须使用一个或者多个”helper”对象, 它会自动备份和恢复指定类型的数据, 这样我们就不用实现onBackup()和onRestore()方法了. Android当前提供的backup helper将会从SharedPreferences和internal storage完整的备份和恢复文件.
鉴于Google服务的可用性, 暂时不做过多的介绍, 详情可以参考这里. 以后或许会补充…
APP安装路径概述:
从Android API 8开始, 我们可以选择APP安装在外部存储中(比如SD卡). 这是一个可选的功能, 我们可以在manifest中的android:installLocation属性定义. 如果我们不声明这个属性, APP将会被安装在内部存储, 并且不能被移动到外部存储.
想要允许系统将APP安装在外部存储, 修改manifest文件包含android:installLocation即可, 值可以设置为”preferExternal”或者”auto”. 栗如:
<manifest xmlns:android="http://schemas.android/apk/res/android"
android:installLocation="preferExternal"
... >
如果选择了”preferExternal”, 就表示我们要求APP被安装在外部存储中, 但是系统不保证APP一定会被安装在外部存储中, 如果外部存储满了或者不可用, 系统会将其安装在内部存储. 用户也可以在内外部存储之间移动APP.
如果选择了”auto”, 表明APP可能被安装在外部存储, 但是我们并不指定安装路径的偏好. 系统将会根据一些因素决定将APP安装在哪. 用户也可以在内外部存储移动APP. 当APP被安装在外部存储的时候:
l 当外部存储mount在了设备上, 那么对APP的性能是没有影响的.
l .apk文件被保存在外部存储中, 但是所有私有的用户数据, 数据库, 优化的.dex文件和提取出的原生代码都会被保存在内部存储中.
l APP被安装的唯一容器会被随机生成的密钥加密, 并且只能由最初安装的设备才能被解密. 因此, 一个被安装在SD卡上的APP只能为一台设备工作.
l 用户可以通过系统设置移动APP到内部存储.
警告: 当用户启用USB块存储来与电脑分享文件的时候, 或者unmount了SD卡的时候, 外部存储中所有的APP将会被直接killed.
向后兼容性:
APP可以安装在外部存储的能力只有在Android2.2及更高版本中使用. 被安装在更早版本中的APP只能被安装在内部存储中, 并且不能移动到外部存储(就算在2.2的版本的设备上也不行). 但是如果我们的APP需要被设计支持比Android 2.2更低的版本, 我们可以选择支持在2.2以上的版本支持该功能, 但是可以兼容2.2以下的版本.
如果想要安装在外部存储并且保存对Android2.2之前版本的兼容性:
1. 在<manifest>标签中包含android:installLocation属性, 并赋予一个”auto”或者”preferExternal”的值.
2. 留下android:minSdkVersion属性, 保持它该使用的值(比8小)并确保APP仅适用该版本可以兼容的代码.
3. 为了编译我们的APP, 修改build target为API Level 8. 这很有必要因为更老的Android库不认识android:installLocation属性, 所以不会编译APP.
当APP被以API Level小于8安装在设备上, android:installLocation属性会被忽略并且APP会被安装在内部存储中.
注意: 尽管XML标记比如android:installLocation将在更老的平台上会被忽略, 我们必须小心在minSdkVersion小于8的时候不要使用在APILevel 8中引入的API, 除非我们的APP有必要在代码中提供向后兼容.
不应该被安装在外部存储的APP:
当用户使用USB mass storage跟电脑共享文件的时候(或者其它的移除外部存储的操作), 任何安装在外部存储的APP将会被立即杀死. 出了杀死APP之外并使其对用户不可用之外, 这还可以以多种方式破坏一些类型的APP. 为了让APP始终像预期的那样运行, 如果APP使用了任何下列列出的功能, 则我们不应该让APP安装在外部存储中
1. Services: APP正在运行的Service将会被杀死, 并且当外部存储重新安装之后不会被重新启动. 但是我们可以注册一个ACTION_EXTERNAL_APPLICATIONS_AVAILABLE广播intent, 它将会在安装在外部存储的APP重新可用的时候提醒APP.这时候可以重新启动Service.
2. Alarm Services: 使用AlarmManager注册的alarm将会被取消. 我们必须在外部存储重新安装后手动重新注册任何alarm.
3. Input Method Engines: 我们的IME将会被默认的IME替代. 当外部存储重新安装后, 用户可以打开系统设置重新设置IME.
4. Live WallPapers: 正在运行的LiveWallPapers将会被默认的Live WallPapers代替. 当外部存储重新安装之后, 用户可以再次选择它.
5. APP Widgets: 我们的APPWidgets将会从桌面移除. 当外部存储重新启用后, APP Widgets将会在系统重置桌面之前变得不可用(通常需要重启).
6. Account Manager: 在外部存储重新安装之前我们用AccountManager创建的账户将会消失.
7. Sync Adapters: 在外部存储重新安装之前我们的AbstractThreadedSyncAdapter和所有它的同步功能将会不能工作.
8. Device Administrators: 我们的DeviceAdminReceiver和它的所有admin功能将会变得不可用. 其后果会导致相关功能的行为不可预知.
9. Broadcast Receivers listeningfor "boot completed": 系统会在外部存储mount到设备之前发出ACTION_BOOT_COMPLETED广播. 如果APP安装在外部存储, 它永远都不会收到这个广播.
如果APP使用任何上述列出的功能, 那么我们不应该让APP安装在外部存储. 默认情况下, 系统不会让APP安装在外部存储, 所以我们不需要为其担忧. 但是如果我们确定APP永远都不该被安装在外部存储, 我们应该设置android:installLocation的值为”internalOnly”. 虽然这不会修改默认行为, 它明确规定了我们的APP应该仅被安装在内部存储并作为一个提醒表示这个决定已经做出了(⊙﹏⊙)b.
应该被安装在外部存储的APP:
简单来说, 任何不使用上述列出的功能的APP安装在外部存储都是很安全的. 大型游戏是最适合安装在外部存储的APP的类型, 因为游戏并不是在关闭的时候应该提供服务的APP. 当外部存储不可用并且一个游戏被杀死的时候, 重新启用外部存储并不会对游戏产生什么影响, 用户重启游戏即可(这里假设游戏在其声明周期方法中保存了游戏的状态).
如果我们的APP需要很大的空间, 则应该考虑安装在外部存储中, 这样可以为用户在内部存储中空出一些空间.(好理想…)
参考: https://developer.android/guide/topics/data/backup.html
https://developer.android/guide/topics/data/install-location.html
更多推荐
Android 数据存数 II-数据备份简介和APP的安装路径
发布评论