好好管理你應用的文件夾,別再亂用了

安卓碎片化的問題,由來已久,此次來看一下文件儲存碎片化的問題。到底要怎麼去正確選擇和管理文件存儲呢?java

爲何要管理文件?

Android手機一直以來被人詬病越用越卡,越用存儲空間越少,常常有要靠各類清理app清理垃圾,到最後不得對手機進行雙清,緣由除了硬件老化和Android的底層實現問題以外,開發者對文件管理的忽視製造出大量沒法清理的「垃圾」也是形成手機卡慢的緣由之一。android

Android的開放性給了開發者巨大的自由度,但自由不是讓咱們濫用權限和隨意開發的藉口,每個開發者都應該注重細節,連曾經一片混亂的第三方推送都開始統一整合規範化了,若是你還在隨意開發,不如如今開始,注重細節,提升用戶的Android手機體驗?api

Android閃存

總所周知,Android手機存儲分爲兩個部分:內部存儲外部存儲,內部存儲通常是手機自帶的存儲空間,外部存儲指外插SD卡提供的存儲空間;隨着手機發展,這兩個存儲的定義又有了一些些變化,新的手機再也不有外插SD卡的概念,採起了內置閃存(eMMC、UFS等)的方式,因此內部存儲和外部存儲在新的Android手機上已經在同一個硬件上了。但爲了兼容舊設備和讓用戶獲得更好的體驗,咱們仍然須要管理好手機上內外存儲的使用。緩存

關於文件存儲位置的api

作過文件相關管理的同窗應該都曾經被android衆多的文件api搞得一片混亂過,如今來理一理.微信

我把應用操做的文件存儲位置分爲三個部分app

  1. 應用內部存儲私有文件目錄
  2. 應用外部存儲私有文件目錄
  3. 公有目錄

咱們有兩種api去獲取這三個部分的存儲位置,它們分別歸屬於Context和Environment。工具

Context

Context是應用的上下文,它用來獲取與應用相關的文件目錄,能夠獲取應用私有和應用公有目錄,經常使用的api有(後面是所對應的路徑):spa

1. Context#getCacheDir()                    /data/user/0/cn.appname.xxx/cache
2. Context#getDir("spanner",MODE_PRIVATE)   /data/user/0/cn.appname.xxx/app_spanner
3. Context#getFileDir()                     /data/user/0/cn.appname.xxx/files
3. Context#getExternalCacheDir()            /storage/emulated/0/Android/data/cn.appname.xxx/cache
4. Context#getExternalFilesDir(Environment.DIRECTORY_PICTURES)  /storage/emulated/0/Android/data/cn.appname.xxx/files/Pictures
   Context#getExternalFilesDir(null)        /storage/emulated/0/Android/data/cn.appname.xxx/files
5. Context#getExternalMediaDirs()           /storage/emulated/0/Android/media/cn.appname.xxx
複製代碼

前兩個是應用內部存儲私有目錄,後面4個都是應用外部存儲私有文件目錄。 注意:/data/user/0/ 等同於 /data/data/code

Environment

Environment和應用無關,它用於獲取公有存儲位置的文件目錄,經常使用的api有:cdn

1. Environment#getExternalStorageDirectory()                /storage/emulated/0
2. Environment#getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)        /storage/emulated/0/DCIM
   Environment#getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES)    /storage/emulated/0/Pictures
3. Environment#getDataDirectory()                           /data
4. Environment#getDownloadCacheDirectory()                  /data/cache
5. Environment#getRootDirectory()                           /system
複製代碼

API的選用

到底何時要用什麼api呢?

應用私有文件目錄

應用私有目錄由Context獲取控制,分爲內部存儲外部存儲,內部存儲不須要申請文件讀寫權限也可以使用,外部存儲須要權限(getetExternalCacheDir() 和 getExternalFilesDir() 這兩個方法從4.4以後再也不須要讀寫權限)。用戶對app進行數據清理或卸載能夠清理外部存儲和內部存儲下的全部文件目錄。

內部存儲

內部存儲的文件夾其餘應用和用戶沒法直接訪問,能夠用於存放敏感數據。

  • getCacheDir()

    • 專門用於存放緩存數據。
    • 用戶對app進行緩存清理的時候會清理緩存目錄cache的數據,手機空間不足的時候系統也會對緩存目錄內的數據進行清理。但儘管如此,開發者仍要管理好緩存數據特別是內部存儲的緩存,避免緩存數據過大。
  • getFileDir()

    • 可用於用於存放私有持久文件。
    • 很是適合用於存放app各類伴隨app運行週期所須要的文件數據,它既不會由於手機存儲空間不足而被清理,也不會因卸載app而遺留數據垃圾,而且它是私有的。
  • getDir(String name,int mode)

    • 歸類存放私有文件。
    • 在內部私有目錄下會建立一個名爲app_name的文件夾,mode之前是能夠設置文件夾私有(MODE_PRIVATE)和公有的(MODE_WORLD_READABLE、MODE_WORLD_WRITEABLE),但目前公有的mode都已經廢棄,意味着這個api建立的文件夾已經徹底私有,不能再共享出去了。

外部存儲

在Android Q以前其餘應用是能夠訪問修改外部存儲的應用私有目錄的,這個要注意。

使用外部存儲以前必定要檢查外部存儲是否可用,由於舊設備不必定會有外部存儲,新手機也不必定會給你讀寫權限,就算用戶不給你權限,你的app也要運行啊,否則就不用你的了。

public static boolean isSDCardEnable() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }
複製代碼
  • getExternalCacheDir()

    • 專門用於存放緩存數據。和內部存儲的getCacheDir()類似。
  • getExternalFilesDir(String type)

    • 歸類存放公有文件。
    • 若是type不爲null的話在外部私有目錄下建立返回一個名爲type的文件夾,爲null直接返回外部私有根目錄。如無特別須要,我的的作法是傳入Environment的DIRECTORY常量進行文件夾建立。
    • 若是看完這篇你還不會選用api,那就把你應用雜七雜八的東西都放進去吧,文件至少不用東一件西一件的,卸載以後也可以被正確清理掉,不過也要控制好佔用的存儲空間。
  • getExternalMediaDirs()

    • 可存放共享媒體文件。
    • 這個是在Android 5.0加入的api,建立和獲取位於/sdcard/Android/media目錄下的應用目錄,該目錄下的文件可以被其餘應用訪問和被MediaStore查詢和獲取。但目前較少開發者在使用這個api。

公有目錄

獲取公有目錄要使用Environment的Api,它返回的目錄全都是共享的公有目錄。形成Android手機文件存儲混亂的罪魁禍首!爲數衆多的無責任開發者在這裏胡亂建立文件夾,亂起名、亂放文件,普通用戶根本沒法判斷哪些文件夾、文件是有用的,卸載app以後留下龐大的沒法清理的垃圾文件,致使手機空間不足。因而它們在Android Q被廢棄了,可是Q以前仍是能好好使用的,我認爲要開始減小使用它們,更多地使用Context下的私有目錄API。

  • getExternalStorageDirectory()

    • 獲取外部存儲(SD卡)的根目錄。使用getExternalStoragePublicDirectory(String)進行替代便可。
  • getExternalStoragePublicDirectory(String type)

    • 使用頻率極高的api,返回在根目錄下的名爲type的文件夾,我把它分爲兩種用法:一種是傳入Environment的DIRECTORY常量再建立子目錄使用;一種是傳入appPackageName或者易被識別歸屬的名稱建立子目錄使用。前者會比較通用,內容能夠被各類工具app搜索發現(包括微信);後者算是私用,能夠存放不跟隨app生命的文件,即卸載後也能夠保留。

    • Environment.DIRECTORY_DCIM是手機的相冊,這個文件夾都是系統相關的app在用,存放相機拍攝的圖片,手機截圖之類的,不推薦開發者使用這個文件夾,避免混亂。值得一提的是淘寶有在使用這個文件夾,用於保存它的商品分享截圖,這個位置的確能夠避免被微信封殺~哈哈

    • Environment.DIRECTORY_PICTURES用於存放各類「正式的」圖片,強烈建議在這裏建立文件夾存放你想要被用戶發現的圖片,而且微信會掃描這個文件夾,讓你的圖片更容易分享。不過還。

    • Environment.DIRECTORY_DOWNLOADS能夠用於存放app更新的apk等下載資源。

    • 其餘幾個比較少用就不介紹了。

適配Android Q

上面提到Environment的兩個公有目錄經常使用API在Android Q被廢棄了,應用存儲功能沙箱化,文件存放到沙箱外面要使用 DocumentFile,共享媒體文件要使用MediaStore進行,詳細的適配已有其餘開發者分享出來了,推薦一下這篇:feng.moe/archives/47…

我很喜歡的承香墨影也出了篇適配指南,內容更加詳細:mp.weixin.qq.com/s/aiDMyAfAZ…

結尾

最後說一下幾個重要的事:

  • 獲取文件路徑這件事永遠不能寫死某個路徑,不存在SD卡怎麼辦呢?某個路徑沒法使用了怎麼辦呢?因此管理文件的時候必需要有存儲策略。好比一個文件的保存地址獲取方法裏不能只有一個api,要保有兜底措施,若是我不能存在外部儲存,那我就存在內部,保證app的功能正常運行。

此次的分享到這裏,但願看完這篇文章以後可以讓你更瞭解如何管理手機文件夾。

相關文章
相關標籤/搜索