Android 數據存數 II-數據備份簡介和APP的安裝路徑

數據備份概述:

Android的backup服務讓我們可以複製自己的持久化數據到遠程”雲”存儲, 可以爲APP數據和設置提供一個還原點. 如果用戶執行了恢復出廠設置或者轉移到了一個新的Android設備, 系統會在APP重新安裝的時候自動還原之前備份的數據. 通過這種方式, 我們的用戶不需要複製它們之前的數據或者APP設置. 這個流程對用戶完全透明而不會影響到APP的功能或者用戶體驗.

在一個備份操作中, Android的備份管理器(BackupManager)查詢我們的APP中的備份數據, 然後告知一個備份運輸組件, 這東西將會把數據傳遞給雲存儲. 在恢復備份的操作中, Backup Manager從備份運輸組件取回備份數據並將它交還給APP, 這樣APP就可以恢復數據到設備了. 我們的APP可以自己主動選擇恢復, 但是通常這是不必要的, 因爲Android會在APP安裝的時候自動執行一個恢復操作(前提是要有相關聯的備份). 所以第一選擇應該是當用戶重置設備或者更新到一個新的設備並且他們之前安裝的APP被重新安裝的時候(自動恢復).

注意: 備份服務不是設計用來爲APP跟其它客戶端同步數據或者保存在普通生命週期中訪問普通數據的. 我們不能在需要的時候去讀寫這些數據也不能通過Backup Manager提供的API用任何方式訪問它們.

備份運輸是Android的backup framework的客戶端組件, 它是由設備生產廠家自定義的service provider. 備份運輸在不同設備間可能會有所差異, 設備提供了怎樣的備份運輸對於我們的APP是透明的. Backup Manager API是APP和真正的備份運輸之間的適配層, 這樣我們的APP只需要跟Backup Manager通信就可以了, 而不用理會底層的實現.

數據備份並不保證在所有的Android設備上可用. 但是我們的APP不會因爲設備不提供一個備份運輸就產生不利影響. 如果開發的時候確信用戶會從數據備份中受益, 那麼可以使用該文檔中描述的來實現它, 測試它, 然後發佈APP而不關心設備如何執行備份. 當APP運行在一個不支持備份運輸的設備上時, 我們的APP會正常運行, 但是將不會收到從Backup Manager發出的回調.

儘管我們不知道當前的備份運輸是什麼, 但是我們的備份數據總是可以保證不被其它的APP訪問到. 只有Backup Manager和備份運輸擁有訪問備份數據的權限.

注意: 因爲雲存儲和運輸服務在設備間可能會有所差異, Android不保證使用數據備份的時候的加密問題. 我們應該總是自己謹慎對待使用備份來保存敏感信息, 比如用戶名和密碼.

數據備份基礎:

想要備份我們的APP數據, 需要先實現一個備份代理. 備份代理被Backup Manager調用來提供我們想要備份的數據. 它也會在數據恢復的時候調用. Backup Manager處理雲存儲中所有的數據交換(使用備份運輸), 備份代理則處理所有的設備上的數據交換. 要實現一個備份代理, 我們必須:

1.      在manifest中用android:backupAgent屬性聲明我們的備份代理.

2.      註冊APP到一個備份服務. Google提供了Android Backup Service作爲大多數的Android設備的備份服務. 它要求我們在使用之前先註冊APP. 任何其它可用備份服務一般也需要先註冊服務, 然後才能提供服務.

3.      通過下面的兩種方式之一定義一個備份代理:

a)        繼承BackupAgent: BackupAgent類提供了APP與BackupManager通信的核心接口. 如果我們直接繼承了該類, 則必須重寫onBackup()和onRestore()方法來處理數據的備份和恢復操作.

b)        繼承BackupAgentHelper: BackupAgentHelper類提供了對BackupAgent的封裝, 使其用法更加的便捷, 它最小化了我們需要實現的代碼. 在我們的BackupAgentHelper中, 必須使用一個或者多個”helper”對象, 它會自動備份和恢復指定類型的數據, 這樣我們就不用實現onBackup()和onRestore()方法了. Android當前提供的backup helper將會從SharedPreferences和internal storage完整的備份和恢復文件.

鑑於Google服務的可用性, 暫時不做過多的介紹, 詳情可以參考這裏. 以後或許會補充…

 

APP安裝路徑概述:

從Android API 8開始, 我們可以選擇APP安裝在外部存儲中(比如SD卡). 這是一個可選的功能, 我們可以在manifest中的android:installLocation屬性定義. 如果我們不聲明這個屬性, APP將會被安裝在內部存儲, 並且不能被移動到外部存儲.

想要允許系統將APP安裝在外部存儲, 修改manifest文件包含android:installLocation即可, 值可以設置爲”preferExternal”或者”auto”. 慄如:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    android:installLocation="preferExternal"
    ... >

如果選擇了”preferExternal”, 就表示我們要求APP被安裝在外部存儲中, 但是系統不保證APP一定會被安裝在外部存儲中, 如果外部存儲滿了或者不可用, 系統會將其安裝在內部存儲. 用戶也可以在內外部存儲之間移動APP.

如果選擇了”auto”, 表明APP可能被安裝在外部存儲, 但是我們並不指定安裝路徑的偏好. 系統將會根據一些因素決定將APP安裝在哪. 用戶也可以在內外部存儲移動APP. 當APP被安裝在外部存儲的時候:

l  當外部存儲mount在了設備上, 那麼對APP的性能是沒有影響的.

l  .apk文件被保存在外部存儲中, 但是所有私有的用戶數據, 數據庫, 優化的.dex文件和提取出的原生代碼都會被保存在內部存儲中.

l  APP被安裝的唯一容器會被隨機生成的密鑰加密, 並且只能由最初安裝的設備才能被解密. 因此, 一個被安裝在SD卡上的APP只能爲一臺設備工作.

l  用戶可以通過系統設置移動APP到內部存儲.

警告: 當用戶啓用USB塊存儲來與電腦分享文件的時候, 或者unmount了SD卡的時候, 外部存儲中所有的APP將會被直接killed.

向後兼容性:

APP可以安裝在外部存儲的能力只有在Android2.2及更高版本中使用. 被安裝在更早版本中的APP只能被安裝在內部存儲中, 並且不能移動到外部存儲(就算在2.2的版本的設備上也不行). 但是如果我們的APP需要被設計支持比Android 2.2更低的版本, 我們可以選擇支持在2.2以上的版本支持該功能, 但是可以兼容2.2以下的版本.

如果想要安裝在外部存儲並且保存對Android2.2之前版本的兼容性:

1.      在<manifest>標籤中包含android:installLocation屬性, 並賦予一個”auto”或者”preferExternal”的值.

2.      留下android:minSdkVersion屬性, 保持它該使用的值(比8小)並確保APP僅適用該版本可以兼容的代碼.

3.      爲了編譯我們的APP, 修改build target爲API Level 8. 這很有必要因爲更老的Android庫不認識android:installLocation屬性, 所以不會編譯APP.

當APP被以API Level小於8安裝在設備上, android:installLocation屬性會被忽略並且APP會被安裝在內部存儲中.

注意: 儘管XML標記比如android:installLocation將在更老的平臺上會被忽略, 我們必須小心在minSdkVersion小於8的時候不要使用在APILevel 8中引入的API, 除非我們的APP有必要在代碼中提供向後兼容.

不應該被安裝在外部存儲的APP:

當用戶使用USB mass storage跟電腦共享文件的時候(或者其它的移除外部存儲的操作), 任何安裝在外部存儲的APP將會被立即殺死. 出了殺死APP之外並使其對用戶不可用之外, 這還可以以多種方式破壞一些類型的APP. 爲了讓APP始終像預期的那樣運行, 如果APP使用了任何下列列出的功能, 則我們不應該讓APP安裝在外部存儲中

1.      Services: APP正在運行的Service將會被殺死, 並且當外部存儲重新安裝之後不會被重新啓動. 但是我們可以註冊一個ACTION_EXTERNAL_APPLICATIONS_AVAILABLE廣播intent, 它將會在安裝在外部存儲的APP重新可用的時候提醒APP.這時候可以重新啓動Service.

2.      Alarm Services: 使用AlarmManager註冊的alarm將會被取消. 我們必須在外部存儲重新安裝後手動重新註冊任何alarm.

3.      Input Method Engines: 我們的IME將會被默認的IME替代. 當外部存儲重新安裝後, 用戶可以打開系統設置重新設置IME.

4.      Live WallPapers: 正在運行的LiveWallPapers將會被默認的Live WallPapers代替. 當外部存儲重新安裝之後, 用戶可以再次選擇它.

5.      APP Widgets: 我們的APPWidgets將會從桌面移除. 當外部存儲重新啓用後, APP Widgets將會在系統重置桌面之前變得不可用(通常需要重啓).

6.      Account Manager: 在外部存儲重新安裝之前我們用AccountManager創建的賬戶將會消失.

7.      Sync Adapters: 在外部存儲重新安裝之前我們的AbstractThreadedSyncAdapter和所有它的同步功能將會不能工作.

8.      Device Administrators: 我們的DeviceAdminReceiver和它的所有admin功能將會變得不可用. 其後果會導致相關功能的行爲不可預知.

9.      Broadcast Receivers listeningfor "boot completed": 系統會在外部存儲mount到設備之前發出ACTION_BOOT_COMPLETED廣播. 如果APP安裝在外部存儲, 它永遠都不會收到這個廣播.

如果APP使用任何上述列出的功能, 那麼我們不應該讓APP安裝在外部存儲. 默認情況下, 系統不會讓APP安裝在外部存儲, 所以我們不需要爲其擔憂. 但是如果我們確定APP永遠都不該被安裝在外部存儲, 我們應該設置android:installLocation的值爲”internalOnly”. 雖然這不會修改默認行爲, 它明確規定了我們的APP應該僅被安裝在內部存儲並作爲一個提醒表示這個決定已經做出了(⊙﹏⊙)b.

應該被安裝在外部存儲的APP:

簡單來說, 任何不使用上述列出的功能的APP安裝在外部存儲都是很安全的. 大型遊戲是最適合安裝在外部存儲的APP的類型, 因爲遊戲並不是在關閉的時候應該提供服務的APP. 當外部存儲不可用並且一個遊戲被殺死的時候, 重新啓用外部存儲並不會對遊戲產生什麼影響, 用戶重啓遊戲即可(這裏假設遊戲在其聲明週期方法中保存了遊戲的狀態).

如果我們的APP需要很大的空間, 則應該考慮安裝在外部存儲中, 這樣可以爲用戶在內部存儲中空出一些空間.(好理想…)

 

參考: https://developer.android.com/guide/topics/data/backup.html

https://developer.android.com/guide/topics/data/install-location.html

 

發佈了81 篇原創文章 · 獲贊 4 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章