《Android应用开发攻略》——2.14 备份Android应用程序数据

2.14 备份Android应用程序数据

Pratik Rupwal
2.14.1 问题
当用户恢复出厂设置或者改用新的Android设备时,应用程序丢失存储数据或者应用程序设置。
2.14.2 解决方案
Android的Backup Manager(备份管理器)能够在应用程序重新安装时自动恢复备份数据或者应用程序设置。
2.14.3 讨论
Android的备份管理器本质上以两种模式运行——备份和恢复。在备份操作期间,备份管理器(BackuManager类)询问应用程序所要备份的数据,并将其放入一个备份传输中,备份传输负责将数据发送到基于云的存储中。在恢复操作期间,备份管理器从备份传输中读取备份数据,并将其返回给应用程序,以便将数据恢复到设备上。应用程序可以请求恢复,但是在应用程序安装且与用户关联的备份数据存在时,Android并不一定执行恢复操作。恢复备份数据主要发生在用户重置设备或者升级到新设备,并且重新安装过去安装的应用程序时。
例2-19展示了为应用程序实现备份管理器以保存应用程序当前状态的方法。
以下是这一过程各个步骤的简单描述:
1 . 在Eclipse中创建BackupManagerExample项目。
2 . 打开layout/backup_restore.xml文件,并插入例2-19中的代码。
3 . 打开values/string.xml文件并插入例2-20中的代码。
4 . 清单文件看上去将类似于例2-21。
5 . 例2-22中的代码完成了应用程序备份管理器的实现。
例2-19:备份/恢复布局

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><ScrollViewandroid:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:layout_weight="1"><LinearLayoutandroid:orientation="vertical"android:layout_width="match_parent"android:layout_height="wrap_content"><TextView android:text="@string/filling_text"android:textSize="20dp"android:layout_marginTop="20dp"android:layout_marginBottom="10dp"android:layout_width="match_parent"android:layout_height="wrap_content"/><RadioGroup android:id="@+id/filling_group"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="20dp"android:orientation="vertical"><RadioButton android:id="@+id/bacon"android:text="@string/bacon_label"/><RadioButton android:id="@+id/pastrami"android:text="@string/pastrami_label"/><RadioButton android:id="@+id/hummus"android:text="@string/hummus_label"/></RadioGroup><TextView android:text="@string/extras_text"android:textSize="20dp"android:layout_marginTop="20dp"android:layout_marginBottom="10dp"android:layout_width="match_parent"android:layout_height="wrap_content"/><CheckBox android:id="@+id/mayo"android:text="@string/mayo_text"android:layout_marginLeft="20dp"android:layout_width="match_parent"android:layout_height="wrap_content"/><CheckBox android:id="@+id/tomato"android:text="@string/tomato_text"android:layout_marginLeft="20dp"android:layout_width="match_parent"android:layout_height="wrap_content"/></LinearLayout></ScrollView>
</LinearLayout>

例2-20:示例使用的字符串

<resources><string name="hello">Hello World, BackupManager!</string><string name="app_name">BackupManager</string><string name="filling_text">Choose Settings for your application:</string><string name="bacon_label">Sound On</string><string name="pastrami_label">Vibration On</string><string name="hummus_label">Backlight On</string><string name="extras_text">Extras:</string><string name="mayo_text">Use Orientation?</string><string name="tomato_text">Use Camera?</string>
</resources>

例2-21:AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.sym.backupmanager"android:versionCode="1"android:versionName="1.0"><uses-sdk android:minSdkVersion="9" /><application android:label="Backup/Restore" android:icon="@drawable/icon"android:backupAgent="ExampleAgent"> <!-- Here you specify the backup agent--><!--Some backup transports may require API keys or other metadata--><meta-data android:name="com.google.android.backup.api_key"android:value="INSERT YOUR API KEY HERE" /><activity android:name=".BackupManagerExample"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity> </application>
</manifest>

例2-22:备份/恢复活动

package com.sym.backupmanager;
import android.app.Activity;
import android.app.backup.BackupManager;
import android.os.Bundle;
import android.util.Log;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RadioGroup;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
public class BackupManagerExample extends Activity {static final String TAG = "BRActivity";static final Object[] sDataLock = new Object[0];static final String DATA_FILE_NAME = "saved_data";RadioGroup mFillingGroup;CheckBox mAddMayoCheckbox;CheckBox mAddTomatoCheckbox;File mDataFile;BackupManager mBackupManager;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.backup_restore);mFillingGroup = (RadioGroup) findViewById(R.id.filling_group);mAddMayoCheckbox = (CheckBox) findViewById(R.id.mayo);mAddTomatoCheckbox = (CheckBox) findViewById(R.id.tomato);mDataFile = new File(getFilesDir(), BackupManagerExample.DATA_FILE_NAME);mBackupManager = new BackupManager(this);populateUI();}void populateUI() {RandomAccessFile file;int whichFilling = R.id.pastrami;boolean addMayo = false;boolean addTomato = false;synchronized (BackupManagerExample.sDataLock) {boolean exists = mDataFile.exists();try {file = new RandomAccessFile(mDataFile, "rw");if (exists) {Log.v(TAG, "datafile exists");whichFilling = file.readInt();addMayo = file.readBoolean();addTomato = file.readBoolean();Log.v(TAG, " mayo=" + addMayo+ " tomato=" + addTomato+ " filling=" + whichFilling);} else {Log.v(TAG, "creating default datafile");writeDataToFileLocked(file,addMayo, addTomato, whichFilling);mBackupManager.dataChanged();}} catch (IOException ioe) {// 在这里进行错误处理!}}mFillingGroup.check(whichFilling);mAddMayoCheckbox.setChecked(addMayo);mAddTomatoCheckbox.setChecked(addTomato);mFillingGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {public void onCheckedChanged(RadioGroup group,int checkedId) {Log.v(TAG, "New radio item selected: " + checkedId);recordNewUIState();}});CompoundButton.OnCheckedChangeListener checkListener= new CompoundButton.OnCheckedChangeListener() {public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {Log.v(TAG, "Checkbox toggled: " + buttonView);recordNewUIState();}};mAddMayoCheckbox.setOnCheckedChangeListener(checkListener);mAddTomatoCheckbox.setOnCheckedChangeListener(checkListener);}void writeDataToFileLocked(RandomAccessFile file,boolean addMayo, boolean addTomato, int whichFilling)throws IOException {file.setLength(0L);file.writeInt(whichFilling);file.writeBoolean(addMayo);file.writeBoolean(addTomato);Log.v(TAG, "NEW STATE: mayo=" + addMayo+ " tomato=" + addTomato+ " filling=" + whichFilling);}void recordNewUIState() {boolean addMayo = mAddMayoCheckbox.isChecked();boolean addTomato = mAddTomatoCheckbox.isChecked();int whichFilling = mFillingGroup.getCheckedRadioButtonId();try {synchronized (BackupManagerExample.sDataLock) {RandomAccessFile file = new RandomAccessFile(mDataFile, "rw");writeDataToFileLocked(file, addMayo, addTomato, whichFilling);}} catch (IOException e) {Log.e(TAG, "Unable to record new UI state");}mBackupManager.dataChanged();}
}

数据备份不能保证在所有Android设备上可用。但是,如果设备没有提供备份传输,应用程序并不会受到不利影响。如果你相信用户将从应用程序的数据备份中获益,就可以按照这个文档中描述的步骤实现、测试这一功能,然后发布应用程序,而不考虑设备是否实际执行备份。当应用程序在不提供备份传输的设备上运行时,它将正常运作,但是不会接受来自备份管理器的回调来备份数据。
尽管你无法知道当前传输手段是什么,但是始终可以确信,备份数据不会被设备上的其他应用程序读取。只有备份管理器和备份传输有权访问备份操作中所提供的数据。
警告: 因为云存储和传输服务在不同的设备上可能有差别,Android不能保证备份中的数据安全。在使用备份存储敏感数据(如用户名和密码)时,应该始终保持警惕。
测试你的备份代理
实现备份代理之后,可以使用bmgr命令,按照如下步骤测试备份/恢复功能:
1 . 在合适的Android系统映像上安装你的应用程序。如果使用模拟器,创建和使用带有Android 2.2(API Level 8)的AVD。如果使用真实设备,设备必须运行Android 2.2或更高版本并内建Android Market。
2 . 确保备份功能启用。如果使用的是模拟器,可以从SDK tools/路径用如下命令启用备份功能:
adb shell bmgr enable true
如果使用的是设备,打开系统设置,选择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步中初始化的所有数据将被恢复。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/281041.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#程序开机启动与获取程序启动路径

写windows工具时&#xff0c;要进行电源管理&#xff0c;需要重启与开关机OS&#xff0c;这样工具就需要自动启动。查了网上很多资料&#xff0c;修改注册列表就可以。 但是&#xff0c;复制几个网站的代码并自己修改都发现不行&#xff0c;最后发现脚本之家这段代码才成功&am…

wpf office 菜单_如何带回Office 2007中的旧菜单

wpf office 菜单Using the new Ribbon feature in Office 2007 takes time to learn…time you don’t have because projects are stacking up. Today we will look at UBitMenu, a utility that puts the familiar Office 2003 menu into the 2007 ribbon. 使用Office 2007中…

Swagger UI 仅为用户暴露已授权终结点

前言当需要在生产环境中提供 Swagger UI 时&#xff0c;我们可以通过身份验证&#xff0c;控制只有授权用户才能访问 Swagger UI 页面。但是我们希望更进一步&#xff0c;每个用户只能看到授权给他的终结点&#xff0c;而不会暴露其他未授权终结点信息。比如&#xff0c; API 提…

php实现约瑟夫环

function king($high,$size){ $monkey range(1, $high); $i 0 ; while (count($monkey)>1) { $i; $head array_shift($monkey); if(($i % $size) ! 0){ array_push($monkey,$head); } } return $monkey[0];} var_dump(king(10,3));转载于:https://www.cnblogs.com/lijint…

微软正式发布Azure Storage上的静态网站

微软正式宣布了Azure Storage上的静态网站&#xff0c;提供了从托管在Azure Storage上的HTML、CSS和JavaScript文件提供内容的能力。静态网站包含内容固定的Web页面&#xff0c;同时仍然允许利用JavaScript等客户端代码来创建丰富的用户体验。 有了这个新功能&#xff0c;继用于…

帝国国王科技大学上机题解(二)

1.找到字符串中出现次数最少的字符 题目描写叙述 给定一个字符串&#xff08;长度小于50&#xff09; 找到该字符串出现次数最少的字符 假设有两个字符出现次数同样&#xff0c;并且均出现最少。那么ASCII码小的字符优先 输入 输入为一行字符串。不含空格 输出 输出出现次数最少…

如何在计算机上阅读漫画书

Reading and organizing a comic book collection on your computer is efficient and a lot of fun. Today we will look at a couple of free applications that allow you to read your favorite comic books on your computer. 在计算机上阅读和组织漫画集非常有效&#xf…

C# WinForm 自启动/模拟开机自动启动

遇到重写启动步骤&#xff0c;C#调试时显得比较折腾&#xff0c;既要等待重启&#xff0c;又要保存当前文件。 让程序自动重启模拟这样电脑重启步骤&#xff0c;显得非常方便。在http://bbs.csdn.net/topics/100187453找到下面代码&#xff0c;直接使用。 ProcessStartInfo p…

工业互联网平台实现路径

我国工业互联网平台建设虽然仍处于产业培育期&#xff0c;但是工业互联网平台也得到了初期的快速发展&#xff0c;得益于平台企业的积极投入和各地工业和信息化主管部门的大力推动&#xff0c;从平台建设推广的经验来看&#xff0c;下面谈一下个人认为传统制造企业平台战略比较…

Javascript基础之-Promise

转载自: http://www.lht.ren/article/3/ Promise是什么呢&#xff1f;根据ecma-262的定义&#xff1a; Promise是一个被用于延时计算的最终结果的占位符 &#xff08;A Promise is an object that is used as a placeholder for the eventual results of a deferred (and possi…

linux进阶命令2

linux进阶命令2 压缩1.压缩的概念1&#xff09;压缩的目的&#xff1a; 在网络传递文件时&#xff0c;可以先将文件压缩&#xff0c;然后传递压缩后的文件&#xff0c;从而减少网络带宽。 接受者接受文件后&#xff0c;解压即可。2&#xff09;压缩的类型 有损压缩、无损压缩。…

PHP经常使用正則表達式汇总

1. 平时做站点常常要用正則表達式&#xff0c;以下是一些解说和样例&#xff0c;仅供大家參考和改动使用&#xff1a; 2. "^\d$"  //非负整数&#xff08;正整数 0&#xff09; 3. "^[0-9]*[1-9][0-9]*$"  //正整数 4. "^((-\d)|…

psa name_Windows 10安全性PSA:启用自动商店更新

psa nameMicrosoft sometimes distributes important security updates through the Microsoft Store. That’s the lesson we’re learning in July 2020, when Microsoft sent an important update for Windows 10’s HEVC codecs not via Windows Update but via the Store.…

C# ListView 简单命令例子

编写工具常用到ListView控件&#xff0c;能简单列出选项&#xff0c;常用到流程校验显示。这里介绍简答显示&#xff0c;添加与删除功能。 1.添加表头&#xff0c;与显示。 this.listView1.Columns.Add("队列", 40, HorizontalAlignment.Left);this.listView1.Column…

C#并行编程-Task

什么是异步同步和异步主要用于修饰方法。当一个方法被调用时&#xff0c;调用者需要等待该方法执行完毕并返回才能继续执行&#xff0c;我们称这个方法是同步方法&#xff1b;当一个方法被调用时立即返回&#xff0c;并获取一个线程执行该方法内部的业务&#xff0c;调用者不用…

手机照片丢失或误删如何恢复

手机照片丢失或误删如何恢复&#xff1f;我们每个人从刚出生就开始拍照片&#xff0c;一周岁照片、二周岁照片、三周岁照片等&#xff0c;因为照片可以记录我们从小到大的模样和变化。无意照片对我们每个人来说都很重要&#xff0c;如果手机突然坏以前的照片都找不到了怎么办呢…

C++学习笔记(二)——交换函数(swap)

这次我们要透过一个简单的函数swap深入理解函数传参的本质以及在C中如何选择传参方式。 先来看第一段程序&#xff1a; void swap(int x, int y) {int temp y;y x;x temp; } 通过main函数的调用&#xff0c;我们发现x,y并未实现交换&#xff1a; int main() {int x 1;int y…

大数据背后是个万亿市场

2014年的GDP中消费占比已经超过了50%&#xff0c;标志着中国经济正在向市场经济转型&#xff0c;消费占GDP50%&#xff0d;70%是中等发达国家向市场经济过渡的一个表现&#xff0c;未来中国经济增长最大的引擎应该来源于消费&#xff0c;特别是个人消费。中国正在经历经济结构调…

ipad iphone开发_如何将iPhone或iPad置于恢复模式

ipad iphone开发If your iDevice starts acting strangely and you’ve run through the gamut of normal troubleshooting fixes, Recovery Mode may be your answer. This lets you easily reset the device and re-install iOS using iTunes. 如果您的iDevice开始运行异常&a…

从三层架构说起,谈谈对历史项目的小改造

web development项目背景说明最近接手一个 “老” 项目的需求修改&#xff0c;项目整体基于 .net core 3.1 平台&#xff0c;以传统的三层架构为基础构建。了解需求后&#xff0c;逐步对原有项目框架进行大概的了解&#xff0c;主要是熟悉一些框架的开发规范&#xff0c;基本工…