The Basics

为了备份应用数据,你需要实现一个 backup agent. 它用来为BackupManager 提供你想要备份的数据,在你重新安装应用时恢复数据。BackupManager 通过backup transport 处理和云存储相关的数据业务,通过你的backup agent 处理设备上的数据相关的业务。

BackupAgent实现步骤:

  1. 在 manifest 文件中声明 android:backupAgent 属性。

  2. 通过backup服务注册你的应用。谷歌为大多数 Android 设备提供了 Android Backup Service,你需要通过这个服务注册你的应用。其他的云服务也需要注册。

  3. 定义你的 backup agent:

    • 扩展 BackupAgent
      重写 onBackup() onRestore()

    • 扩展 BackupAgentHelper
      需要使用多个helper对象自动完成备份及恢复。
      会备份整个文件。

Declaring the Backup Agent in Your Manifest

application标签中声明android:backupAgent.

    ...                        ...            

android:restoreAnyVersion
默认值为false, 设为true 则会在该应用的任何版本恢复数据。

Registering for Android Backup Service

不同的设备对 backup 的支持不同。

    ...    

Extending BackupAgent

一般情况下,因为BackupAgentHelperBackupAgent更方便,所以尽可能使用前者。
然而,如果有以下需求,还是要通过BackupAgent来实现:

  • 对数据进行版本控制

  • 并不想备份整个数据文件

  • 备份数据库中的数据

如果你想要备份SharedPreferences内部存储中的整个文件,简单地使用BackupAgentHelper即可。

Performing backup

oldState
上一次备份的状态,主要是FileDescriptor

// Get the oldState input streamFileInputStream 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}

data
要备份的数据,通过byte字节流的方式存储

// Create buffer stream and data output stream for our dataByteArrayOutputStream bufStream = new ByteArrayOutputStream();DataOutputStream outWriter = new DataOutputStream(bufStream);// Write structured dataoutWriter.writeUTF(mPlayerName);outWriter.writeInt(mPlayerScore);// Send the data to the Backup Manager via the BackupDataOutputbyte[] buffer = bufStream.toByteArray();int len = buffer.length;data.writeEntityHeader(TOPSCORE_BACKUP_KEY, len);data.writeEntityData(buffer, len);

newState
本次备份的状态,作为下次备份时的oldState

Performing restore

data

用来恢复数据的 `BackupDataInput`.

appVersionCode

android:versionCode

newState
恢复后,需要把data里的ParcelFileDescriptor 写到newState中,它会以下次onBackupoldState被用到。

@Overridepublic void onRestore(BackupDataInput 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 BackupDataInput            byte[] dataBuf = new byte[dataSize];            data.readEntityData(dataBuf, 0, dataSize);            ByteArrayInputStream baStream = new ByteArrayInputStream(dataBuf);            DataInputStream in = new DataInputStream(baStream);            // Read the player name and score from the backup data            mPlayerName = in.readUTF();            mPlayerScore = in.readInt();            // 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.writeInt(mPlayerScore);}

Extending BackupAgentHelper

  • SharedPreferencesBackupHelper

  • FileBackupHelper

Backing up SharedPreferences

public class MyPrefsBackupAgent extends BackupAgentHelper {    // The name of the SharedPreferences file    static final String PREFS = "user_preferences";    // A key to uniquely identify the set of backup data    static final String PREFS_BACKUP_KEY = "prefs";    // Allocate a helper and add it to the backup agent    @Override    public void onCreate() {        SharedPreferencesBackupHelper helper =                new SharedPreferencesBackupHelper(this, PREFS);        addHelper(PREFS_BACKUP_KEY, helper);    }}

Note: SharedPreferences are threadsafe, so you can safely read and write the shared preferences file from your backup agent and other activities.

Backing up other files

public class MyFileBackupAgent extends BackupAgentHelper {    // The name of the file    static final String TOP_SCORES = "scores";    static final String PLAYER_STATS = "stats";    // A key to uniquely identify the set of backup data    static final String FILES_BACKUP_KEY = "myfiles";    // Allocate a helper and add it to the backup agent    @Override    public void onCreate() {        FileBackupHelper helper = new FileBackupHelper(this,                TOP_SCORES, PLAYER_STATS);        addHelper(FILES_BACKUP_KEY, helper);    }}

非线程安全,需要手动加锁

// Object for intrinsic lockstatic final Object sDataLock = new Object();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");}@Overridepublic 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);    }}@Overridepublic 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);    }}

Checking the Restore Data Version

android:versionCode
BackupManager恢复数据前会检查versionCode字段,如果待恢复的版本高于当前应用版本,BackupManager不会调用onRestore()来恢复数据。
android:restoreAnyVersion
设定trueorfalse指明你是否希望通过应用的版本来决定是否恢复数据。设为true,那么BackupManager将不会去检查android:versionCode,而是调用你的onRestore()方法。
你可以通过下面的方法来获取appVersionCode.

PackageInfo info;try {    String name = getPackageName();    info = getPackageManager().getPackageInfo(name,0);} catch (NameNotFoundException nnfe) {    info = null;}int version;if (info != null) {    version = info.versionCode;}

Requesting Backup

  • 使用dataChanged()来请求备份,这个不会立即执行,会在未来某个合适的时间内执行

  • 开发时使用bmgr工具来随时备份

Requesting Restore

  • 自动检测备份数据

  • requestRestore()

  • bmgr工具

Testing Your Backup Agent

  1. 安装应用

  2. 确定备份功能可用

    • 使用模拟器
      adb shell bmgr enable true

    • If using a device, open the system Settings, select Backup & reset, then enable Back up my data and Automatic restore.

  3. 在用户改变数据的地方调用dataChanged()
    然后执行:adb shell bmgr backup your.package.name

  1. 初始化备份操作

    adb shell bmgr run

  2. 卸载应用

    adb uninstall your.package.name

  3. 重新安装

更多相关文章

  1. Android 数据存取
  2. Android 之 使用File类在SD卡中读取数据文件
  3. Android发光特效焦点框-遥控器版本
  4. android SQLite数据库用法图文详解(附源码)
  5. [android]数据库SQLiteDatabase简介
  6. eclipse android或者Java应用查看jdk路径和版本与android studio
  7. Android数据库应用(《Android开发入门与实战》选摘)
  8. Android中使用Gson解析JSON数据,以及把JSON数据映射成一个对象

随机推荐

  1. Android(安卓)传感器 I-传感器基本介绍
  2. Android的px,dpi,dip三者的关系详解
  3. Android(安卓)一张图片(BitMap)占用内存的
  4. iPhone和Android的控件对比
  5. APP如何推广?策划APP推广方案的好方法
  6. android 短信接收流程分析——为更好的拦
  7. android 安全讲座第五层(三) android so
  8. 衡量android开发者水平的面试问题-androi
  9. Android的事件分发源码分析,告别事件冲突
  10. 【有人@我】Android中高亮变色显示文本中