Android清单文件详解(四) ---- backupAgent的用法(二)

简介: Android清单文件详解(四) ---- backupAgent的用法(二)

3.从备份中实现恢复


对于上述知识,我们通过一个简单的实例来说明如何实现备份。其实大家都知道,备份是为了以防万一,既然备份了,那么怎么从备份中恢复呢?接下来就对工程稍加改动,从而实现恢复功能,具体步骤如下:


①修改MyBackupAgent类,这里写一些备份数据以便恢复时使用,修改后的代码如下:


public class MyBackupAgent extends BackupAgent {
    private static final String TAG="MyBackupAgent";
    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException {
        Log.e(TAG,"onBackup running");
        ByteArrayOutputStream bufStream=new ByteArrayOutputStream();
        DataOutputStream outWrite=new DataOutputStream(bufStream);
        outWrite.write(1);
        byte[] buffer=bufStream.toByteArray();
        int len =buffer.length;
        data.writeEntityHeader("DATA",len);
        data.writeEntityData(buffer,len);
    }
    @Override
    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException {
        Log.e(TAG,"onRestore running");
    }
    @Override
    public void onCreate() {
        super.onCreate();
        Log.e(TAG, "onCreate running");
    }
}


②修改MainActivity文件,添加按钮执行恢复操作,具体代码如下:

public class MainActivity extends Activity {
    private static final String TAG="MainActivity";
    private Button myBackup;
    private Button restore;
    private BackupManager backupManager;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.myBackup=(Button)findViewById(R.id.myBackup);
        this.backupManager=new BackupManager(this);
        this.myBackup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                backupManager.dataChanged();//此处执行备份
            }
        });
        this.restore=(Button)findViewById(R.id.restore);
        this.restore.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                backupManager.requestRestore(new RestoreObserver() {
                    @Override
                    public void restoreFinished(int error) {
                        super.restoreFinished(error);
                        Log.e(TAG,"restoreFinished running");
                    }
                });
            }
        });
    }}


③运行程序,得到下图:


63.png


只要按照前面的操作做一遍即可。当完成回复操作后,得到如下日志:


64.png


有必要对这个日志进行讲解一下,我们可以看到第1行备份管理器以@pm@为条件检索需要还原的备份数据,这里找到了3个符合条件的数据,分别在2-4这三行。


其次,调用了nextRestorePackage()方法查询下一个需要恢复的应用程序的包名,如第6行所示。


然后,,初始化备份代理类,并调用该类的onCreate()方法,如第7行所示。


再者,查询需要恢复的数据,并调用onRestore()方法执行恢复操作,如8-11行所示。


最后,结束恢复操作并通知应用程序,如18-21行所示。


4.如何使用bmgr工具


此时,我们已经介绍完了备份功能,还原功能及其使用方法。在这个过程中不难发现,bmgr工具起到了至关重要的作用。接下来,我们就将结合bmgr的源代码进一步讲解如何使用这个重要的工具。


bmgr是Android提供的一个shell工具,它使我们能方便地与备份管理器进行交互。但需要注意的是,备份与还原的相关功能只在Android2.2或者更高的版本中才可以使用。


bmgr还提供了一些命令来触发备份和还原操作,因此,我们不需要反复去擦除数据以测试应用程序的备份代理。这里提供的操作主要有强制备份操作,强制还原操作,擦出备份数据以及启用与禁用备份。


①强制备份操作


通常,应用程序必须通过dataChanged()方法来通知备份管理器我们的数据发生了变化,然后备份管理器会在将来的某一个时刻调用实现备份代理的onBackup()方法。此外,还可以使用命令行形式来取代调用dataChanged()方法,其语法结构如下:

adb shell bmgr backup <package-name>


我们先来看看下面的代码片段:

private void doBackup(){
boolean isFull=false;
String pkg=nextArg();
.......
try{
mBmgr.dataChanged(pkg);
}catch(RemoteException e){
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
}


可以看到,备份操作实际上也是执行了一次dataChanged()操作。


当完成以上命令后,备份队列里面就会增加一个备份请求,它会在将来的某一个时刻执行备份,而我们执行一下命令时:

adb shell bmgr run


Android系统的行为将会是怎样的呢?再来看看下面的代码:

private void doRun(){
try{
mBmgr.dataChanged(pkg);
}catch(RemoteException e){
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
}


上面的代码表明当我们执行run命令后,系统会强制执行备份队列的备份请求,因为它执行了备份管理器的backupNow()方法。



②强制还原操作

和备份操作不一样的是,还原操作会立即执行。目前,Android系统提供了两种类型的还原操作:第一种是使用已有的备份数据去还原整个设备的数据,第二种则是使用某个特定的应用程序将已经备份的数据还原。它们的命令格式如下所示:

Ⅰadb shell bmgr restore <token>
Ⅱadb shell bmgr restore <package>


当执行1命令的时候,它会按照token的输入值找到合适的备份数据去还原整个系统。


当执行2命令的时候,与代码中执行备份管理器的requestRestore()方法一样,它会直接调用备份代理类的onRestore()方法。


现在来看看还原操作的源代码:

private void doRestore(){
String arg=nextArg();
....
if(arg.indexOf(',')>=0){
//包名
doRestorePackage(arg);
}else{
try{
long token=Long.parseLong(arg,16);
doRestoreAll(token);
}catch(NumberFormatException e){
.....
}
}
}


从上面的代码可以看到,当输入的是包名时,将执行一个名叫doRestorePackage()的方法,这个方法主要调用了还原接口的restorePackage()方法,用来还原一个应用程序的备份数据。而当输入的是token的时候,则执行了一个名叫doRestoreAll()方法,这个方法调用了还原接口的restoreAll() 方法,将查询到的所有应用程序的备份数据还原到对应的应用程序上去。


③擦除备份数据


该操作用于单一的应用程序数据,它在开发备份代理的时候非常有用。使用bmgr工具的wipe命令,可以擦除应用程序的数据:


adb shell bmgr wipe <package>


其中<package>是应用程序正式的包名称,该应用程序的数据是希望被擦除的。


Android执行该命令的过程如下所示:

private void doWipe(){
String pkg=nextArg();
....
try{
mBmgr.clearBackupData(pkg);
System.out.println("Wiped backup data for"+pkg);
}catch(RemoteException e){
System.err.println(e.toString());
System.err.println(BMGR_NOT_RUNNING_ERR);
}
}


如上面代码第5行所示,此命令执行了备份管理器上的clearBackupData()方法,用于擦除对应应用程序备份的数据。


④启动与禁用备份


使用一下命令,可以查看备份管理器是否是可操作的:


adb shell bmgr enabled


也可以用如下命令来直接禁用或启用备份管理器:

adb shell bmgr enable <boolean>


其中boolean或者为true,或者为false,这与设备的设置里禁用或启用备份是一致的。


作为对知识的深挖,有必要介绍一下备份管理器,方法如下表:


方法原型

说明

使用方法示例

public Backup Manager(Context context) 通过此方法,可通过上下文构造一个备份管理器实例。通过这个实例,我们可以与Android备份系统交互 BackupManager mBackupManager;
mBackupManager=new BackupManager (Context);
public void dataChanged() 调用此方法的目的是通知Android备份系统,应用程序希望备份新的修改到它的备份数据上

mBackupManager.dataChanged();

public static void dataChanged(String packageName) 调用此方法的目的是指明packageName所对应的应用程序为一次备份。
注意:当调用者与参数描述的应用程序包没有运行在相同的uid下时,使用这个方法则需要在引用程序的AndroidManifest.xml文件中声明android.permission.BACKUP权限

mBackupManager.dataChanged("com.example.liyuanjing.helloworld")

public int requestRestore(RestoreObserver observer)

调用此方法是目的是强制从备份数据集中恢复应用程序的数据。

observer是一个恢复执行的观察者用于通知应用程序恢复的执行状态,包括如下的方法。

1.onUpdate():通知调用者应用程序当前的恢复操作正在执行。

2.restoreStarting():通知调用者应用程序当前的恢复操作已经启动。

3.restoreFinished():通知调用者应用程序当前的恢复操作已经完成。

mBackupManager.requestRestore(new RestoreObserver(){

@Override

public void restoreFinished(int error){

super.restoreFinished(error);

}

});


现在大家已经学习如何使用backupAgent类和bmgr工具实现备份与恢复。在使用backupAgent类的过程中,我们发现直接使用这个类来实现备份时,需要管理的细节有很多,这导致使用时不太方便。比如,需要管理备份数据的新老状态以及备份数据的关键字等细节问题。在某些特定的场景下,比如在我们打算备份一个完整的文件时,这些文件可以是保存在内部存储器中的文件或者共享文件等,Android SDK就提供了一个帮助类用以简化代码复杂度,它的名字叫BackupAgentHelper。


Android框架提供了两种不同的帮助类,它们是SharedPreferencesBackupHelper和 FileBackupHelper,前者用于备份SharedPreferences文件,后者用于备份来自内部存储器的文件。


值得注意的是,对于每一个需要加到BackAgentHelper中的帮助类,我们都必须在BackupAgentHelper和onCreate()方法中做两件事:实例化所需要的帮助类,调用addHelper()方法将帮助类添加到BackupAgentHelper中。


下面来尝试修改前面的HelloWorld项目。在这个过程中,我们还将使用BackupAgentHelper类来实现对一个文件的备份,具体操作步骤如下:


①修改MainActivity类,在myBackup按钮的单击事件中写一个文件,并将其存储在内部存储器中。修改后的代码如下所示:

public class MainActivity extends Activity {
    private static final String TAG="MainActivity";
    public  static final String DATA_FILE_NAME="saved_data";
    private Button myBackup;
    private Button restore;
    private BackupManager backupManager;
    public static final Object[] sDataLock=new Object[0];
    private File myFile;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        this.myBackup=(Button)findViewById(R.id.myBackup);
        this.backupManager=new BackupManager(this);
        this.myFile=new File(getFilesDir(),MainActivity.DATA_FILE_NAME);
        this.myBackup.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                synchronized (sDataLock){
                    try {
                        RandomAccessFile file=new RandomAccessFile(myFile,"rw");
                        file.writeInt(1);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    backupManager.dataChanged();//加入备份队列准备备份
                }
            }
        });
        this.restore=(Button)findViewById(R.id.restore);
        this.restore.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                backupManager.requestRestore(new RestoreObserver() {
                    @Override
                    public void restoreFinished(int error) {
                        super.restoreFinished(error);
                        Log.e(TAG,"restoreFinished running");
                    }
                });
            }
        });
        this.initalFile();//初始化文件
    }
    private void initalFile(){
        RandomAccessFile file;
        synchronized (sDataLock){
            boolean exists=this.myFile.exists();
            try {
                file=new RandomAccessFile(this.myFile,"rw");
                if(exists){
                    file.writeInt(1);
                }else{
                    file.setLength(0L);
                    file.write(1);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }}


②新建一个继承自BackupAgentHelper的类来替代原有的BackupAgent子类,用以实现备份及恢复,完成后的代码如下所示:

public class MyBackupAgentHelper extends android.app.backup.BackupAgentHelper {
    private static final String TAG="BackupAgentHelper";
    public static final String FILE_HELPER_KEY="myback";
    @Override
    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState) throws IOException {
        //这里我们无需要做任何任何事情,只需要把它交给框架即可
        synchronized (MainActivity.sDataLock){
            super.onBackup(oldState, data, newState);
        }
        Log.e(TAG,"onBackup is running");
    }
    @Override
    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState) throws IOException {
        //这里我们无需要做任何任何事情,只需要把它交给框架即可
        synchronized (MainActivity.sDataLock){
            super.onRestore(data, appVersionCode, newState);
        }
        Log.e(TAG,"onRestore is running");
    }
    @Override
    public void onCreate() {
        //这里我们首先实例化一个FileBackupHelper实例
        //并使用它作为参数之一调用addHelper()方法完成初始化
        FileBackupHelper file_helper=new FileBackupHelper(this,MainActivity.DATA_FILE_NAME);
        addHelper(FILE_HELPER_KEY,file_helper);
    }
}


③修改AndroidManifest.xml文件中的android:backupAgent,将MyBackupAgentHelper作为其属性


④编译并运行应用程序。此时,当单击应用程序的“Backup”按钮并运行adb shell bmgr run命令之后,Android就开始备份了。但当单击应用程序的restore按钮时,Android将恢复这个文件。


到这里,我们就介绍完Android:backupAgent属性的作用及其用法了。

相关文章
|
16天前
|
移动开发 安全 Java
Android历史版本与APK文件结构
通过以上内容,您可以全面了解Android的历史版本及其主要特性,同时掌握APK文件的结构和各部分的作用。这些知识对于理解Android应用的开发和发布过程非常重要,也有助于在实际开发中进行高效的应用管理和优化。希望这些内容对您的学习和工作有所帮助。
155 83
|
5月前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
|
7月前
|
Java Android开发 C++
Android Studio JNI 使用模板:c/cpp源文件的集成编译,快速上手
本文提供了一个Android Studio中JNI使用的模板,包括创建C/C++源文件、编辑CMakeLists.txt、编写JNI接口代码、配置build.gradle以及编译生成.so库的详细步骤,以帮助开发者快速上手Android平台的JNI开发和编译过程。
467 1
|
6月前
|
编解码 前端开发 Android开发
Android经典实战之TextureView原理和高级用法
本文介绍了 `TextureView` 的原理和特点,包括其硬件加速渲染的优势及与其他视图叠加使用的灵活性,并提供了视频播放和自定义绘制的示例代码。通过合理管理生命周期和资源,`TextureView` 可实现高效流畅的图形和视频渲染。
437 12
|
5月前
|
ARouter Android开发
Android不同module布局文件重名被覆盖
Android不同module布局文件重名被覆盖
262 0
|
7月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
241 1
|
7月前
|
存储 监控 数据库
Android经典实战之OkDownload的文件分段下载及合成原理
本文介绍了 OkDownload,一个高效的 Android 下载引擎,支持多线程下载、断点续传等功能。文章详细描述了文件分段下载及合成原理,包括任务创建、断点续传、并行下载等步骤,并展示了如何通过多种机制保证下载的稳定性和完整性。
209 0
|
8月前
|
Android开发 Kotlin
Android经典面试题之Kotlin中Lambda表达式有哪些用法
Kotlin的Lambda表达式是匿名函数的简洁形式,常用于集合操作和高阶函数。基本语法是`{参数 -&gt; 表达式}`。例如,`{a, b -&gt; a + b}`是一个加法lambda。它们可在`map`、`filter`等函数中使用,也可作为参数传递。单参数时可使用`it`关键字,如`list.map { it * 2 }`。类型推断简化了类型声明。
54 0
|
9月前
|
Java 开发工具 Android开发
详细解读Android开发DNK开发将.c文件打包成os
详细解读Android开发DNK开发将.c文件打包成os
46 0
|
9月前
|
Android开发
Android Gradle开发—脚本实现自动打包后复制一份APK文件,并修改APK名称,到指定目录作备份
Android Gradle开发—脚本实现自动打包后复制一份APK文件,并修改APK名称,到指定目录作备份
445 0

热门文章

最新文章

  • 1
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 2
    Android历史版本与APK文件结构
  • 3
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
  • 4
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 5
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 6
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 9
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 1
    android FragmentManager 删除所有Fragment 重建
    17
  • 2
    Android实战经验之Kotlin中快速实现MVI架构
    25
  • 3
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    33
  • 4
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    42
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    134
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    41
  • 7
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    55
  • 8
    Android历史版本与APK文件结构
    155
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    48
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    40