安卓存儲空間


安卓存儲空間

安卓存儲結構

首先明確一下新時代下,安卓內部存儲和外部存儲的概念。我使用的是MIUI12系統,打開文件管理,只能看到內部存儲設備。在傳統概念中,內部存儲設備就是手機自帶的空間,外部存儲設備是SD卡,但是現在就沒有SD卡了,全部用內部存儲設備實現,怎么去理解呢?

先看個圖了解安卓的文件結構:

  • /data/data/

    apk的安裝目錄。 如:百度地圖的安裝路徑是/data/data/com.baidu.com/ 注意:該目錄需要獲取root權限才能查看

  • /system/

    存放系統應用的apk文件,即手機廠商預安裝應用的apk文件 (手機廠商只需把需要預安裝的apk放在該節點的相應路徑下,android系統就會自己解壓並安裝該apk)

  • /storage/

    該節點是內置存儲卡和外置SD卡的掛載點,/storage/emulated/0/是內置存儲卡掛載點, /storage/sdcard1是外置SD卡掛載點(不同的設備掛載節點不一樣,有些設備可能會掛載到/mnt/節點)。

在AS中寫入代碼:

//這個方法在API30下已經被廢棄了
val dir = Environment.getExternalStorageDirectory()

谷歌官方給這個方法的注釋(部分):

這個方法返回主共享/外部存儲目錄。如果該目錄已由用戶安裝在其計算機上、已從設備中刪除或發生了其他一些問題,則當前可能無法訪問該目錄。您可以使用 getExternalStorageState() 確定其當前狀態。
注意:不要被這里的“外部”一詞混淆。這個目錄最好被認為是媒體/共享存儲。它是一個文件系統,可以保存相對大量的數據,並在所有應用程序之間共享(不強制執行權限)。傳統上這是一個 SD 卡,但它也可以作為設備中的內置存儲實現,該設備與受保護的內部存儲不同,可以作為文件系統安裝在計算機上。

就是說,外部存儲空間作為一個文件系統,被實現在內置存儲設備中。

同時,安卓鼓勵的是應用運行時重要必須的數據放在內部存儲中,而在外部存儲空間去進行大文件的存放和共享。

我們上面提到了內置存儲卡,它被視為外部存儲空間, 所以如果我們嘗試打印相關信息:

// 被廢棄了,但是依然可以打印出來,在開發中不推薦用
Log.d("外部存儲根目錄", "${Environment.getExternalStorageDirectory()}")

顯示的是 :D/外部存儲根目錄: /storage/emulated/0

則明確了外部存儲的根目錄是內置存儲卡, 可以理解為燒在主板上的一個硬盤(個人理解)

應用專屬存儲

內部存儲空間

我們可以在內部存儲空間給應用創建目錄或者文件

這些目錄既包括用於存儲持久性文件的專屬位置,也包括用於存儲緩存數據的其他位置。系統會阻止其他應用訪問這些位置,並且在 Android 10(API 級別 29)及更高版本中,系統會對這些位置進行加密。這些特征使得這些位置非常適合存儲只有應用本身才能訪問的敏感數據。 ——Google

內部存儲空間中的根目錄為/data,下面討論在內部存儲空間中的用戶專屬存儲

我們發現,在context中可以直接調出已經封裝好了的用戶專屬存儲的目錄:

Log.d("本地文件目錄", "${this.filesDir}")
Log.d("本地數據目錄", "${this.dataDir}")
Log.d("本地緩存目錄","${this.cacheDir}")

顯示內容:

D/本地文件目錄: /data/user/0/com.example.myapplication/files
D/本地數據目錄: /data/user/0/com.example.myapplication
D/本地緩存目錄: /data/user/0/com.example.myapplication/cache

這些目錄我們可以直接利用來進行創建目錄,文件來存取數據,而不需要申請權限

例如,在本地數據目錄下創建一個目錄, 采用了Context.MODE_PRIVATE參數:

val dir = getDir("f",Context.MODE_PRIVATE)
Log.d("文件夾", "${dir}")

顯示:D/文件夾: /data/user/0/com.example.myapplication/app_f

我們可以在這個文件夾下創建並寫入文件(包含內容)

val file = File(dir, "fff.txt")
val fw = FileWriter(file).use {
	it.write("牛逼666")
    it.close()
}

我們之后在開發的過程中,可以參照上述簡單例子的方法,創建內部專屬目錄並存儲文件。

我們也可以把暫時需要的文件寫入緩存中,例如用戶需要更換頭像裁剪生成的中間圖片,或者用戶加載的內容不期望二次加載,我們都可以把它們存入緩存文件中

在我的上一篇博客中,就把裁剪圖片的目標地址定位在緩存文件中, 部分代碼:

val  outpurDir = this.cacheDir
	if(outpurDir.exists()){
	cacheFile = File(outpurDir, "${System.currentTimeMillis()}_cache.png")
}

// 在緩存位置的基礎上生成Uri
var mPhotoUri = Uri.fromFile(cacheFile)

內部專屬存儲空間就大概了解到這里。

外部存儲空間

我們已經知道,現在的新手機基本采用的是內置存儲卡,雖然在用戶的角度上看不出內部存儲空間和內部存儲卡的區別(用戶只知道容量為128G),但開發者還是應該有意的把大文件存儲在外部存儲空間上。

我們可以在外部存儲空間上,開設應用私有的存儲空間。雖然寫在了外部存儲空間上,應用被卸載時,這些內容要是會被系統移除。

我們要把什么內容存在上面呢?把一些私有的媒體文件存儲在上面合適,避開MediaStore的掃描,讓其他的應用無法獲取

通過context可以直接獲取到外部存儲空間的目錄:

Log.d("外部存儲文件目錄", "${this.getExternalFilesDir("MUSIC")}")

顯示內容為:D/外部存儲文件目錄: /storage/emulated/0/Android/data/com.example.myapplication/files/MUSIC

這樣創建的音樂目錄,MediaStore無法掃描,在安卓10,安卓11下,其他應用也無法直接訪問到這個位置,它是安全的。

但我們發現可以獲取一個外部的媒體目錄(具體做什么現在還不清楚),但可以被MediaStore掃描到

Log.d("外部存儲文件目錄", this.externalMediaDirs.get(0).absolutePath)

顯示內容:

D/外部存儲文件目錄: /storage/emulated/0/Android/media/com.example.myapplication

所以私有媒體內容我們不應該存入這個文件夾,它很可能被共享(暫未驗證)

共享空間

這里的共享是針對應用而言的,例如相冊就是一個典型的共享空間,應用都可以去訪問相冊

Android 提供用於存儲和訪問以下類型的可共享數據的 API:

  • 媒體內容:系統提供標准的公共目錄來存儲這些類型的文件,這樣用戶就可以將所有照片保存在一個公共位置,將所有音樂和音頻文件保存在另一個公共位置,依此類推。您的應用可以使用此平台的 MediaStore API 訪問此內容。
  • 文檔和其他文件:系統有一個特殊目錄,用於包含其他文件類型,例如 PDF 文檔和采用 EPUB 格式的圖書。您的應用可以使用此平台的存儲訪問框架訪問這些文件。

媒體內容

這里不做具體的操作介紹,具體的操作介紹直接參考 官方文檔

Mediastore是什么呢,官方稱為:

經過優化的媒體集合索引

我們可以把它理解為一個數據庫,它的查詢方式和SQL數據庫查詢很類似。

注意的是,在安卓10之后,我們要添加媒體文件都要先生成Uri

文檔和其他文件

由於這部分還沒有具體使用過,很陌生,具體參考 官方文檔

文檔和其他特殊文件的操作流程大致為:

系統把文檔提供器封裝為了一個Activity,通過啟動回調的方式來選擇文檔和處理文檔

分區存儲

在過去,即API<29時,如果我們去訪問外部存儲,都需要申請權限,無論是訪問媒體庫,還是訪問我們應用專屬分區文件,在早一點的版本,還可以去訪問其他應用創建的文件。

為了讓用戶更好的管理文件,減少混亂,加強安全等級, 分區存儲從API29開始提出,API30開始,強制進行分區存儲。

分區存儲不允許應用去讀取其他應用的存儲空間,不允許隨意讀取共享空間(限制了共享的范圍),同時我們訪問媒體庫和應用在外部存儲上的專屬空間時,不再需要申請權限。

參考 這篇博客,列出分區存儲中的一些規則:

  • 應用訪問自己的應用目錄不受限制 無需任何權限
  • 應用向媒體集和下載目錄提供文件,如果您要想保存圖片、視頻、音頻、文檔,無需任何權限
  • 不再提供寬泛的共享存儲, 讀寫存儲權限只能訪問提供的媒體集 ( 圖片集視頻集音頻集下載集 )
  • 位置元數據限制,獲取圖片上的位置等信息需要請求權限,如果不請求權限,讀取圖片的信息的時候,位置元數據將會被刪除
  • 讀取 PDF其他類型的文件,需要調用系統的文件選擇器 ( Storage Access Framerwork API )
  • 在媒體集或應用目錄之外,寫任何文件都需要系統的文件選擇器 , 這樣用戶能選擇並確認將文件存在哪里

我們實際操作時,可以概括為以下兩點:

  • 特定於應用的目錄中的文件(使用 getExternalFilesDir() 訪問,上述例子給出)。
  • 應用創建的照片、視頻和音頻片段(通過媒體庫訪問), 盡可能的使用MediaStore去操作

回顧我上一篇博客中從相冊選取圖片和裁剪圖片的例子,都是依照分區存儲的思路去處理的,效果很好。

總結

本文淺顯地對了解到的安卓存儲相關知識的進行了概括。

在應用開發過程中,存儲相關內容十分重要,好的存儲組織可以提高效率和優化用戶體驗。后續還會繼續深入學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM