了解 Android 應用的文件存儲目錄,掌握持久化數據的正確姿勢

本文導讀:在安卓手機上,安裝或者卸載一個 App,會涉及到本地存儲系統的哪些目錄結構變化?作為開發人員,如何恰當地存儲應用相關的信息?相關存儲目錄的生命周期、訪問方式和訪問權限又是怎樣的呢?帶著這些問題,希望讀完這篇文章,你能夠有所收獲。

內部存儲空間中的應用私有目錄


對于設備中每一個安裝的 App,系統都會在內部存儲空間的 data/data 目錄下以應用包名為名字自動創建與之對應的文件夾。這個文件夾用于 App 中的 WebView 緩存頁面信息,SharedPreferences 和 SQLiteDatabase 持久化應用相關數據等。

對于沒有 Root 過的手機,普通用戶是無法查看 data/data 目錄內容的。不過開發人員可以使用模擬器調試應用,并通過 DDMS(Dalvik Debug Monitor Server)提供的 File Explorer 工具查看模擬器設備的存儲空間。

操作路徑:

第一步:Android Studio --> Tools --> Android --> Android Device Monitor;

第二步:Window --> Show View --> Android --> File Explorer。

Android SDK 提供有如下方法可以獲取并操作內部存儲空間下應用私有目錄文件的方,都位于 Application Context 中,供開發者直接調用:

  • getFilesDir()

  • getCacheDir()

  • deleteFile()

  • fileList()

等等,也可以通過 Environment 類訪問:

Environment.getDataDirectory();

注意:當用戶卸載 App 時,系統自動刪除 data/data 目錄下對應包名的文件夾及其內容。

外部存儲空間中的應用私有目錄


考慮內部存儲空間容量有限,普通用戶不能直接直觀地查看目錄文件等其他原因,Android 在外部存儲空間中也提供有特殊目錄供應用存放私有文件,文件路徑為:

/storage/emulated/0/Android/data/app package name

備注:一般設備都有內置 SD 卡,同時也提供外部 SD 卡拓展,可能對應路徑的目錄名有所差異。

值得注意的是,與內部存儲空間的應用私有目錄不同的是:

第一,默認情況下,系統并不會自動創建外部存儲空間的應用私有目錄。只有在應用需要的時候,開發人員通過 SDK 提供的 API 創建該目錄文件夾和操作文件夾內容。

第二,自 Android 7.0 開始,系統對應用私有目錄的訪問權限進一步限制。其他 App 無法通過 file:// 這種形式的 Uri 直接讀寫該目錄下的文件內容,而是通過 FileProvider 訪問。(關于這個內容,接下來再寫一篇文章專門說說 7.0 的適配問題,歡迎關注我的微信公眾號:安卓筆記俠。)

第三,宿主 App 可以直接讀寫內部存儲空間中的應用私有目錄;而在 4.4 版本開始,宿主 App 才可以直接讀寫外部存儲空間中的應用私有目錄,使開發人員無需在 Manifest 文件中或者動態申請外部存儲空間的文件讀寫權限。

而相同點在于:同屬于應用私有目錄,當用戶卸載 App 時,系統也會自動刪除外部存儲空間下的對應 App 私有目錄文件夾及其內容。

同樣,Android SDK 中也提供有便捷的 API 供開發人員直接操作外部存儲空間下的應用私有目錄:

  • getExternalFilesDir()

  • getExternalCacheDir()

等等,當然,也可以通過 Environment 類間接操作,只不過需要向用戶申請操作權限:

Environment.getExternalStorageDirectory();

類似于 File 和 Cache 默認分類目錄,開發人員也可以在應用私有目錄中創建屬于自己的自定義目錄,方便于分類存儲應用相關文件。

值得注意的一點是,對于外部存儲空間下的應用私有目錄文件,由于普通用戶可以自由修改和刪除,開發人員在使用時,一定要做好判空處理和異常捕獲,防止應用崩潰退出!

外部存儲空間中的公共目錄


通常來說,應用涉及到的持久化數據分為兩類:應用相關數據和應用無關數據。前者是指專供宿主 App 使用的數據信息,比如一些應用的配置信息,數據庫信息,緩存文件等。當應用被卸載,這些信息也應該被隨之刪除,避免存儲空間產生不必要的占用。

相對而言,后者更偏向于這類信息:當應用被卸載,用戶仍然希望保留于設備當中的信息。常見如,拍照類應用的圖片文件,用戶是使用瀏覽器手動下載的文件等。

顯然,無論是內部存儲空間,還是外部儲存空間,上述兩個應用私有目錄由于其特有的生命周期(隨著應用卸載而自動清除)只適合存儲應用相關數據。

或者從訪問權限上來說,應用無關數據應該是宿主應用希望與其他應用共享這些數據的,應該存放在外部存儲空間的公共目錄文件夾下。

外部存儲空間已經為用戶默認分類出一些公共目錄。開發人員可以通過 Environment 類提供的方法直接獲取相應目錄的絕對路徑,傳遞不同的 type 參數類型即可:

Environment.getExternalStoragePublicDirectory(String type);

Envinonment 類提供諸多 type 參數的常量,比如:

  • DIRECTORY_MUSIC:Music

  • DIRECTORY_MOVIES:Movies

  • DIRECTORY_PICTURES:Pictures

  • DIRECTORY_DOWNLOADS:Download

等等,以第一個常量為例,音樂類別的公共目錄絕對路徑為:/storage/emulated/0/Music。如果你使用文件管理器打開設備的外部存儲空間的話,均可以看到這些公共目錄文件夾。

面對如此諸多的默認類別,開發人員在保存自己應用的公共文件時,也要養成良好的習慣,將要保存的數據分門別類地保存在不同公共目錄下。當然,你也可以在公共目錄下再次創建屬于自己應用的目錄,便于管理。

注意:訪問外部存儲空間時記得申請讀寫權限!

外部存儲空間中的其他目錄


一般來說,利用兩種應用私有目錄和公共目錄便能夠存儲應用中需要保存的數據和文件。如果這些還不夠的話,那一定是你的開發姿勢不對。在 Code Review 的前提下,如果還是不夠的話,還可以在外部存儲空間自由創建其他目錄,通過這個方式獲取外部存儲空間的絕對路徑,然后操作文件:

Environment.getExternalStorageDirectory();

小結


使用應用私有目錄保存應用相關數據,使用公共目錄保存應用無關數據(共享數據)。無論哪種情況,都需要做好數據分類保存,便于清除等統一管理。隨便打開手機上的幾個應用,不難發現,很多應用都包含一個清理緩存的功能。事實上,開發人員清理的就是應用相關數據,也就是應用私有目錄下的文件。

考慮到外部存儲空間上的內容可能被用戶手動刪除,或者卸載拓展 SD 卡等不可控因素,操作前記得使用 Environment 類提供的 API 方法判斷容量是否充足、文件是否存在等情況,做好異常捕獲,減少應用崩潰率。相信這一定是一個良好的習慣。

更多存儲選項和存儲框架,參考開發者官網:

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容