Android 儲存概覽

莱布尼茨發表於2024-08-22

儲存區​

Android 一開始就將儲存區分為內部儲存外部儲存,對應手機自帶的儲存和可插拔的 sd 卡(可類比於 PC 的硬碟和 隨身碟)。

內部儲存容量有限,Google 建議 App 資料儘量儲存於外部儲存中。

隨著硬體技術發展,自帶大容量空間的手機開始出現,關於內部儲存的描述逐漸偏離現實了,於是從 Android 4.4(API 19)開始,官方不再將機身儲存等同於內部儲存,而是從邏輯上將其一部分劃到外部儲存,限制剩下那部分的容量,也就是現在所謂的內部儲存。這一操作,使得原本內部儲存和外部儲存的特性和使用場景得以延續。

當然,如果在 4.4 系統及以上的手機上插了 sd 卡,那麼 sd 卡也屬於外部儲存。

我們可以使用如下程式碼列印出所有的外部儲存:

File[] files;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    files = getExternalFilesDirs(Environment.MEDIA_MOUNTED);
    for(File file:files){
        Log.e("main",file);
    }
}

對於 4.4 以上的插了 sd 卡的大容量手機,應該會列印出如下資訊:

/storage/emulated/0/Android/data/packname/files/mounted 
/storage/B3E4-1711/Android/data/packname/files/mounted 

檔案

應用專屬檔案

僅供應用使用的檔案,可以儲存到內部儲存或外部儲存中的本應用專屬目錄,本應用訪問時不需要任何許可權。在資料安全方面,雖然都是專屬目錄,但是內部儲存可以保證其它應用訪問不到,而外部儲存就比較複雜了。

在較低版本的 Android 系統中,只要宣告READ_EXTERNAL_STORAGE許可權就能訪問位於外部儲存空間中應用專屬目錄之外的任何檔案;只要宣告WRITE_EXTERNAL_STORAGE許可權就能嚮應用專屬目錄以外的任何檔案寫入資料。

這實在是相當危險,誰也不希望自家應用中的資料被抓取或篡改。於是從Android 10(API 29)開始有了分割槽儲存的概念,應用在預設情況下就能訪問外部儲存空間上自己的專屬目錄,以及本應用所建立的特定型別的媒體檔案(使用MediaStore API,下面會講到)。如此,除非特殊情況,應用不再需要宣告上述許可權了。

此時,如果應用在執行時請求與儲存相關的許可權,將會彈出請求對話方塊(動態申請)表明應用正在請求對外部儲存空間的廣泛訪問許可權。

Android 11(API 30)開始更進一步,乾脆將 WRITE_EXTERNAL_STORAGE 許可權的作用抹除(即使宣告瞭該許可權也沒用)。這將應用的寫許可權完全限制在了本應用相關目錄(專屬目錄和本應用建立的媒體檔案)中。

ps:Android 11 引入了_MANAGE_EXTERNAL_STORAGE_許可權,該許可權替代 WRITE_EXTERNAL_STORAGE,提供對應用專屬目錄和 MediaStore 之外檔案的寫入許可權,但對使用的要求更嚴格。如需瞭解詳情,請參閱有管理儲存裝置上所有檔案

共享檔案

儲存您的應用打算與其它應用共享的檔案,包括媒體(圖片、音訊檔案、影片)、其它型別檔案。

媒體檔案

使用 MediaStore API 訪問。注意:即使您的應用已解除安裝,作為共享檔案(儲存在媒體庫中)的媒體檔案仍會保留在使用者的裝置上。

除訪問自己的媒體檔案外,訪問其它應用的媒體檔案需要許可權——在 Android 11(API 30)或更高版本中,需要 READ_EXTERNAL_STORAGE;在 Android 10(API 29)中,需要 READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE;在更低版本中,訪問所有檔案均需要相關許可權。——不過這也不是絕對的。

比如照片選擇器,它提供了一個可瀏覽介面,為使用者提供了一種安全的內建授權方式,讓使用者可以嚮應用授予限於所選圖片和影片的訪問許可權,而非整個媒體庫的訪問許可權,該許可權保留至裝置重啟或應用停止執行。使用照片選擇器可以看作定製的動態申請許可權的介面,至少從Android 13(API 32)開始,無需事先宣告 READ_EXTERNAL_STORAGE。

其它檔案

自 Android 4.4(API 19)始,官方提供了儲存訪問框架,便於應用與外部儲存卷和雲端儲存空間在內的文件提供器互動。此框架支援使用者與系統選擇器互動,從而選擇文件提供器以及供您的應用建立、開啟或修改的特定文件和其它檔案。

同照片選擇器類似,由於使用者參與選擇您的應用可以訪問的檔案或目錄,因此該機制無需任何系統許可權,同時使用者控制和隱私保護也得到了增強。

這些檔案儲存在應用專屬目錄和媒體庫之外,且在應用解除安裝後仍會保留在裝置上。

使用儲存訪問框架涉及以下步驟:

  1. 應用呼叫包含儲存相關操作的 intent(ACTION_CREATE_DOCUMENT儲存檔案;ACTION_OPEN_DOCUMENT開啟檔案;ACTION_OPEN_DOCUMENT_TREE授予應用對該目錄中所有檔案和子目錄的訪問許可權)。
  2. 使用者看到一個系統選擇器,供其瀏覽文件提供器並選擇將執行儲存相關操作的位置或文件。
  3. 應用獲得對代表使用者所選位置或文件的 URI 的讀寫訪問許可權。利用該 URI,應用可以在選擇的位置執行操作。

資料

應用配置項

不贅述,就是簡單的鍵值對。值得一提的是,之前都是使用SharedPreferences進行應用配置項的操作,現在官方建議使用Jetpack DataStore,允許您使用協議緩衝區儲存鍵值對或型別化物件。DataStore 基於Kotlin 協程Kotlin.Flow以非同步、一致的事務方式儲存資料。

資料庫

基於SQLite的資料儲存,一般選擇Jetpack.Room這個半 ORM 簡化資料 CRUD 操作。解除安裝應用時資料庫會跟著刪除。

相關文章