- Android 系统概述
- 什么是智能手机?智能手机操作系统有哪些?
- Android(安卓)是什么?
- Android 系统架构(图解)
- Android 7 新特性介绍
- Android 开发环境搭建
- Android 开发环境搭建教程(图解)
- Android SDK 是什么?
- 通过 Android Studio 创建 Android 应用程序(附带解析)
- Android Studio 的基本调试
- Android 应用程序结构:Android 组件和资源详解
- Android 四大核心组件:Activity+Service+BroadcastReceiver+ContentProvider
- Android Activity 组件及其生命周期
- Android 资源(res 和 assets 目录)
- AndroidManifest.xml 配置文件详解
- Android App Widgets 组件详解
- Android 系统的进程和线程
- Android GUI(图形用户界面)开发
- Android View 和 ViewGroup
- Android 使用 XML 文件定义用户界面
- Android 五大布局:FrameLayout、LinearLayout、AbsoluteLayout、RelativeLayout 和 TableLayout
- Android 创建 Widget 组件实例详解
- Android Button:按钮控件
- Android CheckBox:多选按钮控件
- Android RadioGroup:单选按钮控件
- Android TextView:文本框控件
- Android EditText:编辑框控件
- Android Spinner:下拉列表控件
- Android AutoCompleteTextView:自动完成文本框控件
- Android DatePicker 和 TimePicker:时间日期选择器
- Android ProgressBar:进度条控件
- Android ScrollView:滚动视图
- Android SeekBar:拖动条控件
- Android RatingBar:评价条控件
- Android ImageView 和 ImageButton:图片视图和图片按钮
- Android ImageSwitcher 和 Gallery:图片切换器和图库
- Android GridView:网格视图
- Android Tab:面板标签控件
- Android 菜单:选项菜单+上下文菜单+子菜单
- Android Bitmap(点阵图像、绘制图像)
- Android 对话框(AlertDialog+ProgressDialog)
- Android 多窗口模式(分屏模式)
- Android 事件监听器和回调方法
- Android 电话短信拍照开发教程
- Android Intent:不同应用程序之间通信的桥梁
- Android 实现拨打电话功能
- Android 实现接收短信和发送短信功能
- Android 调用相机进行拍照
- Android 多媒体开发
- Android Service 生命周期和使用方法
- Android BroadcastReceiver:接收广播
- Android 音频以及音频播放器开发实例
- Android MediaRecorder 录制音频
- Android 视频以及视频播放器实例
- Android Camera 相机以及相机程序开发实例
- Android MediaRecorder 录制视频
- Android 数据存储(SQLite 数据库、Android App 数据备份和恢复 )
- Android 数据存储之 SharedPreferences
- Android 数据存储之文件存储
- Android 使用 SQLite 数据库存数数据
- Android SQLite 数据库操作实例
- Android ContentProvider(内容提供者)
- Android 使用系统提供的 ContentProvider
- Android 自定义 ContentProvider
- Android 使用自定义 ContentProvider
- Google App Engine 是什么?
- Android APP 数据备份与恢复
- Android BackupAgent 实现数据备份与恢复
- Android BackupAgentHelper 实现数据备份与恢复
- Android 网络编程
- 借助 GPE 让 Android APP 和 Google App Engine 通信
- Android HTTP 通信
- Android HttpURLConnection 访问互联网资源
- Android 通过 GET 方式获取互联网资源
- Android 通过 POST 方式获取互联网资源
- Android Socket 编程(附带实例)
- Bluetooth(蓝牙)是什么?
- Android 蓝牙通信开发教程(详解版)
- Android 蓝牙通信开发实例演示
- WIFI(无线局域网)是什么?
- Android WiFi 开发(WiFi 编程)实例演示
- WIFI Direct(WIFI 直连)是什么?
- Android WIFI Direct 开发教程
- Android WIFI Direct 开发实例演示
- NFC(近场通信)是什么?
- Android NFC 开发教程
- Android USB 开发简介
- Android USB 附件模式开发教程
- Android USB 主机模式开发教程
- Android SIP 开发教程
- Android 智能传感器
- LBS(位置服务)和 GPS(全球定位系统)简介
- Android LBS 位置服务开发简介
- Android GPS 定位开发教程
- Google Map API 开发简介
- Android Google Map API Key 详细申请步骤
- Google Map API 开发 Android 地图应用实例
- Android 传感器开发教程
- Android 运动传感器开发教程
- Android 位置传感器开发教程
- Android 环境传感器开发教程
- Android 绘图(2D 绘图、3D 绘图)
- Android 2D 绘图开发简介
- Android 使用自定义 View 绘图
- Android 使用 Bitmap 绘图
- Android 使用 SurfaceView 绘制静态图像
- Android 使用 SurfaceView 绘制动态图像
- Android Drawable 开发简介
- Android 3D 绘图开发简介
- Android 硬件加速开发简介
- Android RenderScript 开发简介
- Android App 的国际化和本地化
- Android 国际化和本地化开发简介
- Android 手机区域设置详细步骤
- Android 未本地化应用开发教程
- Android 本地化应用开发教程
- Android 文本输入与复制粘贴
- Android 剪贴板框架开发简介
- Android 剪贴板数据转文本开发简介
- Android 复制粘贴开发教程
- Android Content Provider 复制复杂数据开发教程
- Android 一键复制粘贴开发实例
- Android 企业级应用开发
- Android 设备管理 API 概述
- Android 开发设备管理 API 应用教程
- Android 文本语音 API 开发教程
- Android TV 应用开发教程
- Android TV 应用开发实例
- Android 可穿戴设备应用开发教程
- Android 应用程序的发布
- Android 应用程序发布的步骤
- Android 为什么要为应用程序签名?
- Android 导出未签名应用程序开发步骤
- Android 生成签名文件开发教程
- Android 应用程序签名开发教程
- zipalign 工具优化应用程序开发简介
- Google Play Store( Android Market)发布简介
Android BackupAgent 实现数据备份与恢复
大多数应用程序不需要直接继承 BackupAgent 类,而是继承 BackupAgentHelper 类,并利用 BackupAgentHelper 内建的 helper 类自动备份和恢复文件。
不过,以下三种情况需要直接继承 BackupAgent 类来实现备份代理:
- 将数据格式版本化。例如,需要在恢复数据时修正格式,可以建立一个备份代理,在数据恢复过程中,如果发现当前版本和备份时的版本不一致,可以执行必要的兼容性修正工作。
- 不是备份整个文件,而是指定备份部分数据以及恢复部分数据到设备。
- 备份数据库中的数据。若应用程序使用了 SQLite 数据库并且希望当用户重装应用程序时能够恢复数据库中的数据,则需要建立一个自定义的 BackupAgent。它在备份操作时从数据库中读取合适的数据,在恢复数据操作时建立数据表并插入数据。
通过继承 BackupAgent 类创建备份代理时,必须实现以下两个方法:
- onBackup():备份管理器在程序请求进行备份操作后将调用该方法。在该方法中实现从设备读取应用程序数据,并把需备份的数据传递给备份管理器的操作。
- onRestore():备份管理器在恢复数据时调用该方法。备份管理器调用该方法时将传入备份的数据,并通过该方法将数据恢复到设备上。
1)备份数据
应用程序发出数据备份请求时,备份管理器将调用 onBackup() 方法。在此方法内必须把要备份的数据提供给备份管理器,然后将数据保存到云存储中。
只有备份管理器能够调用备份代理中的 onBackup() 方法。当数据发生改变并需要执行备份时,需要调用 dataChanged() 方法发起备份请求。
备份请求并不会立即导致 onBackup() 方法的调用,备份服务器会等待合适的时机,为上次备份操作后又发出备份请求的所有应用程序执行备份操作。
onBackup() 方法需要传入三个参数,所代表的意义分别如下。
名称 | 作用 |
---|---|
oldState | 表示已打开的、只读的文件描述符 ParcelFileDescriptor,指向应用程序提供的上次备份数据状态的文件。该文件不是来自云存储的备份数据,而是记录上次调用 onBackup() 备份数据相关状态信息的本地文件。 onBackup() 不能读取保存于云存储的数据,可以根据此信息来判断数据自上次备份以来是否变动过。 |
Data | BackupDataOutput 对象,用于将要备份的数据传给备份管理器。 |
newState | 表示已打开的、可读写的文件描述符 ParcelFileDescriptor,指向一个用于将提交给 data 参数的数据相关状态信息写入的文件,状态信息可以简单到只是文件的最后修改时间。 备份管理器下次调用 onBackup() 时,该对象作为 oldState 传入。若没有向 newState 写入信息,则备份管理器下次调用 onBackup() 时 oldState 将指向一个空文件。 |
利用以上参数可以实现 onBackup(),方法如下:
1) 通过比较 oldState,检查自上次备份以来数据是否发生过改变。从 oldState 读取信息的方式取决于当时写入的方式(见步骤 3)。
最简单的记录文件状态的方式是写入文件的最后修改时间戳。以下是从 oldState 读取并比较时间戳的代码:
// 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 }
如果数据没有发生变化,就不需要进行备份,请跳转到步骤 3。
2)在和 oldState 比较后,如果数据发生了变化,就把当前数据写入 data 以便将其返回并上传到云存储中。
必须以 BackupDataOutput 中的“entity“方式写入每一块数据。
一个 entity 是一个二进制数据记录,使用一个唯一的字符串键值进行标识。因此,所备份的数据集实际上是一组键值对。要在备份数据集中增加一个 entity,必须:
- 调用 writeEntityHeader() 方法,传入代表要写入数据的唯一字符串键值和数据大小。
- 调用 writeEntityData() 方法,传入存放着数据的字节缓冲区,以及需从缓冲区写入的字节数,该字节数应该与传给 writeEntityHeader() 的数据大小一致。
下面的示例代码演示了把一些数据拼接为字节流并写入一个 entity 的过程:
// 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);
需要备份的每一块数据都要执行一次该操作。如何将数据切分为 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() 方法来发起恢复数据的请求。
当备份管理器调用 onRestore() 方法时,传入以下三个参数。
- Data:BackupDataInput 对象,用以读取备份数据。
- appVersionCode:整型数据,表示备份数据时,应用程序的 manifest 的 android:versionCode 属性。可以用于核对当前应用程序版本并确定数据格式的兼容性。
- newState:已打开的、可读写的文件描述符 ParcelFileDescriptor,指向一个文件,用于写入最后一次提交 data 数据的备份状态。本对象在下次调用 onBackup() 方法时作为 oldState 返回。
在实现 onRestore() 时,应该对 data 调用 readNextHeader(),以遍历数据集里所有的 entity。对其中每个 entity 需进行以下操作:
1)用 getKey() 方法获取 entity 的键值。
2)将此 entity 键值和已知键值清单进行比较,这个清单应该已经在 BackupAgent 继承类中作为字符串常量定义。一旦键值匹配其中一个键,就执行读取 entity 数据并保存到设备的操作:
- 用 getDataSize() 读取 entity 数据大小并据其创建字节数组。
- 调用 readEntityData(),传入字节数组作为获取数据的缓冲区,并指定起始位置和读取字节数。
- 字节数组将被填入数据,按需读取数据并写入设备即可。
3)把数据读出并写回设备以后,把数据的状态写入 newState 参数。
下面的实例代码将前面的例子中所备份的数据进行了恢复:
@Override public void onRestore (BackupDatalnput 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 BackupDatalnput byte[] dataBuf=new byte[dataSize]; data.readEntityData (dataBuf, 0, dataSize) ; ByteArraylnputStream baStream=new ByteArraylnputStream (dataBuf) ; DatalnputStream in=new DatalnputStream (baStream) ; // Read the player name and score from the backup data mPlayerName=in.readUTF(); mPlayerScore=in.readlnt(); // 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.writelnt (mPlayerScore); }
在以上代码中,传给 onRestore() 的 appVersionCode 参数没有被用到。如果用户程序的版本降低,比如从 1.5 降到 1.0,可能就会用此参数来选择备份数据。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论