Android清單文件詳解(四) ---- backupAgent的用法

      網友投稿 931 2022-05-30

      節點中有一個非常重要的屬性,那就是backupAgent。這里我們將它單獨列出來,從基本含義,用法及其相關屬性等方面來詳細介紹一下。

      1.backupAgent簡介

      android:backupAgent用來設置備份代理。對于大部分應用程序來說,都或多或少保存著一些持久性的數據,比如數據庫和共享文件,或者有自己的配置信息。為了保證這些數據和配置信息的安全性以及完整性,Android提供了這樣一個機制。

      我們可以通過這個備份機制來保存配置信息和數據以便為應用程序提供恢復點。如果用戶將設備恢復出廠設置或者轉換到一個新的Android設備上,系統就會在應用程序重新安裝時自動恢復備份數據。這樣,用戶就不需要重新產生它們以前的數據或者設置了。這個進程對于用戶是完全透明的,并且不影響其自身的功能或者應用程序的用戶體驗。

      在備份操作的過程中,Android備份管理器查詢應用程序需要備份的數據,接著將這些數據發送到備份傳輸點上,由備份傳輸點發送到云存儲器上。

      在恢復操作中,備份管理器從備份傳輸點中檢索到備份數據并且將它返回到應用程序上,這樣該程序就能將數據恢復到設備上了。恢復操作也可以由應用程序主動發起,在應用程序被安裝并且存在與用戶相關的備份數據時,Android能自動恢復操作。恢復備份數據主要發生在兩個場景,一是在用戶重置設備或者升級到新設備后,二是以前裝過的應用程序再次被安裝的時候。

      另外,我們需要注意,備份服務不能將數據傳輸到另一個客戶端上,不能用于保存應用程序生命周期中需要訪問的數據,不能任意讀寫,且只能通過備份服務來訪問。

      備份傳輸點是Android備份框架的客戶端組件,它是由設備制造商以及服務提供商定制的。備份傳輸點對于不同的設備或許不同,并且對于應用程序是透明的。備份管理器API使得應用程序獨立于實際的備份傳輸,也就是說,應用程序通過一套固定的API與備份管理器進行通信,不管底層傳輸如何處理。但不是所有設備都支持備份,不過這不會對應用程序的運行產生任何負面影響。

      2.如何使用backupAgent來實現備份

      為了實現應用程序數據的備份,就必須實現一個備份代理。實現的備份代理是由備份管理器調用的,它用來提供需要備份的數據。當重新安裝應用程序時,它也可以被調用以便于恢復備份數據。

      要實現備份代理,就必須做兩件事,一是實現BackupAgent或者BackupAgentHelper的子類,二是在Manifest文件內用android:backupAgent屬性聲明備份代理。

      首先,我們來看看BackupAgent類提供的方法,如下表所示:

      然后,我們通過一個簡單的實例來說明上表中一些重要方法的調用時間點,包括onBackup(),onCreate()和onRestore()。在這個實例中,僅僅在里面添加一些日志來說明問題,具體步驟如下:

      ①還是以前面的HelloWorld為例,創建一個HelloWorld,或者刪除掉前面的實驗代碼,恢復剛創建時候的樣子。

      ②在應用程序項目中添加一個繼承自BackupAgent的類,名叫MyBackupAgent

      ③添加完MyBackupAgent類后,這個類中已經默認添加了onBackup()和onRestore()兩個回調方法。這里我們還需要添加onCreate()回調方法。

      ④在各個回調方法中添加打印日志的代碼,完成后的代碼如下所示:

      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"); } @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"); }

      ⑤將MyBackupAgent類配置到AndroidManifest.xml中,代碼如下所示:

      ⑥此時我們就已經完成基本配置。通過上面的描述可知,執行備份有兩種方法,一種是通過BackupManager.dataChanged()方法執行備份,另一種則是通過bmgr工具執行備份。這里我們首先演示第一種方法。在創建項目時,默認生成的MainActivity.java文件和AndroidManifest.xml文件使其具有備份的功能。此外,還要添加一個按鈕,這個按鈕的作用是當你單擊它后執行備份動作。修改后的代碼如下:

      public class MainActivity extends Activity { private Button myBackup; 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();//此處執行備份 } }); }}

      ⑦完成了這些工作,就可以開始執行一次備份。需要說明是,我們的測試可能在真機或者模擬器上巡行的時候要確保備份功能處于打開狀態,因此,我們執行如下命令:

      adb shell bmgr enabled

      如果得到提示是“Backup Manager currently disable”,則說明備份管理器處于禁用狀態,此時就需要執行步驟8啟用備份管理器,否則,可以跳過這個步驟。

      ⑧使用以下命令啟用備份管理器:

      adb shell bmgr enable true

      值得注意的是,這個時候單擊按鈕,代碼就強制執行了backupManager.dataChanged(),但此時Android系統只是簡單地將這次備份請求加入了備份消息隊列中,并沒有執行MyBackupAgent的onBackup()方法。要執行備份與還原,還需要繼續完成下面的步驟。

      ⑨使用bmgr工執行一次備份操作,相關命令如下所示:

      adb shell bmgr run

      所有的命令步驟如下圖:

      此時我們會得到如下所示的執行結果:

      現在來解讀一下這個日志。

      第一,通過日志的1-4行可以看到,此時備份管理器(BackupManagerService)已經做好了備份的準備。

      第二,通過日志的第5行到最后一行可以看到,這時的Android正在執行一個備份任務,這個任務做了很多重要的工作,具體如下:

      ㈠初始化實現的備份代理類,并調用類的onCreate()方法。

      ㈡執行備份并調用實現的備份代理類的onBackup()方法。

      ㈢完成以后會形成一個LocalTransport:。

      此時值得注意的是,當執行 adb shell bmgr run命令后,它會通知ActivityThread我們需要一個備份代理,然后由ActivityThread按照輸入到ActivityThread中的參數找到需要初始化的備份代理MyBackAgent,接著它會回調onCreate()方法做一次初始化操作,最后備份服務會回調onBackup()方法,開始執行真正的備份。

      還有另一種方法,如下所示:

      沒有執行第9步的時候,通過在按鈕的單擊事件中添加dataChanged()方法來對備份隊列進行操作。不過,bmgr工具提供了另一個手段來完成dataChanged()所做的事情:

      adb shell bmgr backup you.package.name

      對于應用程序來說,這個命令應該是adb shell bmgr backup com.example.liyuanjing.helloworld。執行此命令后,在執行adb shell bmgr run 命令,將會有相同的結果。

      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"); } }); } }); }}

      ③運行程序,得到下圖:

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

      有必要對這個日志進行講解一下,我們可以看到第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

      我們先來看看下面的代碼片段:

      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

      Ⅱadb shell bmgr restore

      當執行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命令,可以擦除應用程序的數據:

      Android清單文件詳解(四) ---- backupAgent的用法

      adb shell bmgr wipe

      其中是應用程序正式的包名稱,該應用程序的數據是希望被擦除的。

      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或者為true,或者為false,這與設備的設置里禁用或啟用備份是一致的。

      作為對知識的深挖,有必要介紹一下備份管理器,方法如下表:

      現在大家已經學習如何使用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屬性的作用及其用法了。

      Android

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:excel表格中制作多層柱狀圖表的方法是什么
      下一篇:計算機網絡經典面試題30問
      相關文章
      国产精品亚洲自在线播放页码| 国产亚洲精品拍拍拍拍拍| 国产亚洲精品美女2020久久| 久久精品国产亚洲αv忘忧草| 亚洲黄色网址大全| 亚洲男人天堂av| 亚洲毛片在线观看| 亚洲AV本道一区二区三区四区| 精品久久香蕉国产线看观看亚洲| 亚洲日韩中文字幕日韩在线| 亚洲黄黄黄网站在线观看| 亚洲高清成人一区二区三区| 亚洲av无码专区在线观看素人| 在线播放亚洲精品| 亚洲精品视频在线观看你懂的| 亚洲AV无码成人精品区大在线| 亚洲电影日韩精品| 国产精品亚洲mnbav网站| 国产啪亚洲国产精品无码| 亚洲乳大丰满中文字幕| 亚洲啪啪AV无码片| 久久精品国产亚洲AV果冻传媒| 久久综合日韩亚洲精品色| 亚洲av日韩av天堂影片精品| 婷婷亚洲综合五月天小说| 在线电影你懂的亚洲| 亚洲国产综合精品| 涩涩色中文综合亚洲| 亚洲av午夜电影在线观看| 极品色天使在线婷婷天堂亚洲| 亚洲高清最新av网站| 中文字幕亚洲电影| 久久亚洲精品成人| 亚洲精品456在线播放| 亚洲av永久无码精品三区在线4| 欧洲 亚洲 国产图片综合| 亚洲AV无码成人精品区日韩| 亚洲乱人伦精品图片| 亚洲男人都懂得羞羞网站| 亚洲精品高清国产麻豆专区| 亚洲人成电影网站|