open.weixin.qq.com/connect/oauth2/authorize (引用的文章地址)
方便以后查找才復(fù)制文章
前言
這篇文章解析 Android 設(shè)備上數(shù)據(jù)持久化存儲(chǔ)方式角钩,數(shù)據(jù)存儲(chǔ)方式包括共享首選項(xiàng)膨蛮、內(nèi)部存儲(chǔ)琴拧、外部存儲(chǔ)氢哮、SQLite 數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)連接五種存儲(chǔ)方式,方式的選取取決于使用者的需求,如果對(duì)持久化存儲(chǔ)方式不了解播急,那么一定會(huì)有這么幾個(gè)疑問(wèn):
清理緩存,清理的是哪里售睹?
清理數(shù)據(jù)桩警,清理的是哪里?
應(yīng)用私有文件放在哪里昌妹?
公共文件存放在哪里捶枢?
如果你對(duì)以上存在疑問(wèn),那么看完本章后相信可以解開(kāi)你的疑惑飞崖,還會(huì)加深對(duì)數(shù)據(jù)持久化存儲(chǔ)的理解烂叔。
準(zhǔn)備知識(shí)
理解 Android 系統(tǒng)中的內(nèi)部存儲(chǔ)和外部存儲(chǔ)空間的區(qū)別,通過(guò) Android Studio3.0 Device File Explorer 查看 Android 手機(jī)頂級(jí)系統(tǒng)目錄
關(guān)注 data 和 storage 目錄蚜厉,內(nèi)部存儲(chǔ)空間指的是 data目錄,外部存儲(chǔ)空間指的是 storage目錄畜眨,下面來(lái)細(xì)說(shuō)這兩個(gè)目錄:
data 目錄內(nèi)主要目錄是由存放所有應(yīng)用數(shù)據(jù)的 data目錄和存放所有應(yīng)用程序的 app 目錄組成昼牛。安裝應(yīng)用的時(shí)候是把 APK 數(shù)據(jù)提取到 app 目錄內(nèi),而 data目錄是 app 目錄內(nèi)應(yīng)用產(chǎn)生數(shù)據(jù)的存放處康聂,各個(gè)應(yīng)用數(shù)據(jù)以包名分割開(kāi)贰健,該 data 目錄是內(nèi)部存儲(chǔ)私有目錄,內(nèi)容會(huì)隨著應(yīng)用卸載而清除恬汁。
應(yīng)用內(nèi)部存儲(chǔ)空間內(nèi)會(huì)有以下幾個(gè)常見(jiàn)目錄:
/data/data/包名/shared_prefs
/data/data/包名/databses
/data/data/包名/files
/data/data/包名/cache
shared_prefs 是 SharedPreference 創(chuàng)建的文件伶椿;databases是數(shù)據(jù)庫(kù)創(chuàng)建的文件;files 存放應(yīng)用創(chuàng)建文件;cache 存儲(chǔ)臨時(shí)緩存文件脊另,這些目錄都是應(yīng)用私有目錄导狡。
那么如何獲取私有目錄,因?yàn)楹蛻?yīng)用相關(guān)偎痛,所以私有目錄通過(guò) context 對(duì)象獲取旱捧,以下目錄都屬于內(nèi)部存儲(chǔ)私有目錄:
getCacheDir()
獲取緩存目錄。該目錄用于緩存臨時(shí)數(shù)據(jù)踩麦,不能永久存儲(chǔ)數(shù)據(jù)枚赡,因?yàn)楫?dāng)設(shè)備的內(nèi)部存儲(chǔ)空間不足時(shí),Android 系統(tǒng)會(huì)刪除這些緩存文件以回收空間谓谦。為了 APP 高效管理存儲(chǔ)空間贫橙,應(yīng)該自行維護(hù)文件,不應(yīng)該依賴(lài)系統(tǒng)來(lái)清理反粥。系統(tǒng)應(yīng)用管理點(diǎn)擊清除緩存的時(shí)候卢肃,私有目錄內(nèi)只有緩存目錄的數(shù)據(jù)會(huì)被清除,如果點(diǎn)擊的是清除數(shù)據(jù)星压,那么私有目錄內(nèi)即包名下的所有文件都會(huì)被清除践剂。該目錄對(duì)其他或者用戶(hù)不可見(jiàn),敏感數(shù)據(jù)應(yīng)該存放在此目錄下娜膘。
getDir(String name, int mode)
在內(nèi)部私有根目錄下(包名下)創(chuàng)建 name目錄逊脯,目錄名稱(chēng)任意字符串,函數(shù)返回 File 對(duì)象竣贪,如果name目錄不存在會(huì)創(chuàng)建目錄军洼。
getFilesDir()
獲取存放文件的目錄,該目錄可以存放持久文件演怎,只要應(yīng)用不卸載匕争。
openFileOutput(String name, int mode)
在 getFilesDir() 下打開(kāi)或創(chuàng)建文件,如果存在則打開(kāi)爷耀,不存在則創(chuàng)建新文件甘桑,可以通過(guò)write() 方法寫(xiě)入文件,文件存儲(chǔ)在 getFilesDir() 目錄內(nèi)歹叮。
openFileInput(String name)
打開(kāi)指定文件跑杭,如果文件存在則返回 FileInputStream 對(duì)象,操作對(duì)象可以讀取文件內(nèi)容咆耿,文件不存在拋出 FileNotFoundException 異常德谅。
storage 目錄是外部存儲(chǔ)目錄。外部存儲(chǔ)可以是可移除存儲(chǔ)介質(zhì)(SD卡)或內(nèi)部存儲(chǔ)(不可移除)萨螺,通過(guò)文件管理器看到的都是外部存儲(chǔ)目錄窄做,外部存儲(chǔ)目錄又分為公有目錄和私有目錄愧驱。外部存儲(chǔ)公有目錄下的文件所有應(yīng)用都有訪問(wèn)、修改椭盏、刪除權(quán)限组砚,應(yīng)用的卸載不會(huì)影響公有目錄文件,應(yīng)用訪問(wèn)公有目錄需要申請(qǐng)權(quán)限庸汗;私有目錄默認(rèn)僅供應(yīng)用本身訪問(wèn)惫确,不需要申請(qǐng)權(quán)限,可以讀取/寫(xiě)入內(nèi)容蚯舱;如果訪問(wèn)非私有目錄改化,需要申請(qǐng)文件權(quán)限。應(yīng)用卸載后枉昏,私有目錄和內(nèi)容將全部被清除陈肛,下面介紹這兩個(gè)目錄如何獲取:
公有目錄獲取
公有目錄與 Context 無(wú)關(guān)兄裂,使用 Environment 獲取
Environment.getExternalStoragePublicDirectory(Stringtype)
如果要獲取公有根目錄使用無(wú)參數(shù)函數(shù)獲取句旱,如下:
Environment.getExternalStoragePublicDirectory()
以下type是公有文件常見(jiàn)的存儲(chǔ)位置
Environment.DIRECTORY_PICTURES 圖片目錄
Environment.DIRECTORY_DCIM 相冊(cè)目錄
Environment.DIRECTORY_DOCUMENTS 文檔目錄
Environment.DIRECTORY_DOWNLOADS 下載目錄
Environment.DIRECTORY_MOVIES 視頻
私有目錄獲取
私有目錄和 Context 相關(guān),所以使用 context.getExternalXXX 獲取目錄晰奖,以下目錄范圍都屬于外部存儲(chǔ)私有目錄內(nèi):
getExternalFilesDirs() 獲取文件根目錄谈撒,應(yīng)用不卸載,可以長(zhǎng)期存放文件匾南。
getExternalFilesDirs(int type) 獲取文件內(nèi)的具體目錄啃匿。通過(guò) type 參數(shù)指定,type 類(lèi)型和公有目錄類(lèi)型一致
getExternalCacheDir() 獲取緩存目錄蛆楞。該目錄用于存放臨時(shí)私有文件溯乒,如果系統(tǒng)應(yīng)用管理內(nèi)點(diǎn)擊清除緩存,那么該目錄下所有內(nèi)容被清除豹爹,如果點(diǎn)擊的是清除數(shù)據(jù)裆悄,那么整個(gè)私有目錄(包名)和內(nèi)容都會(huì)被清除。
getExternalMediaDirs() 獲取應(yīng)用存放媒體目錄臂聋。目錄內(nèi)的內(nèi)容可以被其他應(yīng)用訪問(wèn)光稼,通過(guò) MediaStore 可以查詢(xún)和獲取。 再普及一個(gè)小知識(shí)孩等,在 Android6.0 及以上版本中來(lái)看兩個(gè)絕對(duì)路徑:
/data/data/com.example.interviewroad/shared_prefs
/data/user/0/com.example.interviewroad/shared_prefs
這兩條絕對(duì)路徑指向同一個(gè)文件艾君。這是因?yàn)?Android 6.0 支持多用戶(hù),文件的實(shí)際路徑是 /data/user/0/XXX(0代表的用戶(hù)ID)瞎访,而 /data/data/XXX 是為了方便查看數(shù)據(jù)而創(chuàng)建的引用目錄腻贰,實(shí)際指向 /data/user/0/XXX吁恍,下文有時(shí)會(huì)出現(xiàn) /data/data/XXX 和 /data/user/0/XXX表述的是一樣的意思扒秸,如果是 Android 5.0 及以下版本播演,返回的是 /data/data/XXX, 這下完全明白了。
把準(zhǔn)備知識(shí)看懂了伴奥,前言中提到的問(wèn)題可以輕松解決写烤。下面開(kāi)始解析Android數(shù)據(jù)持久化的方式。
共享首選項(xiàng)
共享首選項(xiàng)這個(gè)名字聽(tīng)起來(lái)有點(diǎn)陌生拾徙,其實(shí)是 SharedPreference 類(lèi)洲炊,Android 中文網(wǎng)官網(wǎng)這么翻譯,我覺(jué)得以后要習(xí)慣這叫法尼啡,具體用法相信大家已經(jīng)非常熟就不造輪子了暂衡,來(lái)看一段代碼
privatevoidstoreSharedPreferences(){SharedPreferencessharedPreferences=getSharedPreferences("My_Pref_File",Context.MODE_PRIVATE);SharedPreferences.Editoredit=sharedPreferences.edit();edit.putBoolean("silentMode",true);edit.commit();}
這段代碼會(huì)在 Android 設(shè)備上創(chuàng)建 My_Pref_File.xml 文件,文件內(nèi)存放了一對(duì)布爾類(lèi)型的鍵值對(duì)崖瞭,鍵為 silentMode狂巢,值為true。My_Pref_File.xml 文件存放在內(nèi)部存儲(chǔ)空間內(nèi)书聚,來(lái)看一張截圖唧领,這張圖是通過(guò) Android Studio3.0 新增特性 Device File Explorer 查看
My_Pref_File.xml 文件位于 /data/user/0/com.example.interviewroad/shared_prefs 目錄下,該目錄屬于內(nèi)部存儲(chǔ)空間雌续,所以SharedPreference類(lèi)創(chuàng)建的文件所在目錄位于/data/user/0/包名/shared_prefs/目錄下斩个,位于內(nèi)部存儲(chǔ)私有目錄下。
使用內(nèi)部存儲(chǔ)
1驯杜、內(nèi)部存儲(chǔ)保存文件:
使用 openFileOutput(String name, int mode) 函數(shù)受啥,返回 FileOutputStream 對(duì)象。
調(diào)用 FileOutputStream 對(duì)象的 write() 函數(shù)艇肴。
關(guān)閉流對(duì)象腔呜,調(diào)用 close() 方法。
讀取使用 openFileInput(String name)再悼,使用完后也要關(guān)閉流對(duì)象核畴。
如果需要讀取 /res/raw/ 下的文件,使用 getResources().openRawResource(X)冲九,X 為資源 ID 即 R.raw.谤草,返回InputStream對(duì)象。
代碼如下:
StringFILENAME="hello_file";
Stringstring="hello world!";
FileOutputStreamfos=openFileOutput(FILENAME,Context.MODE_PRIVATE);
fos.write(string.getBytes());
fos.close();
以上代碼會(huì)創(chuàng)建 hello_file 文件莺奸,文件存放在 /data/data/包名/files 目錄下丑孩,使用 context.getFilesDir() 獲取。
2灭贷、內(nèi)部存儲(chǔ)內(nèi)放緩存文件:
主要用于緩存數(shù)據(jù)温学,而不是持久化數(shù)據(jù),通過(guò) getCacheDir() 獲取緩存目錄甚疟,該目錄僅供于存放臨時(shí)文件仗岖,應(yīng)用清除緩存時(shí)逃延,會(huì)清理該目錄,詳細(xì)說(shuō)明也在準(zhǔn)備知識(shí)中講到轧拄。
使用外部存儲(chǔ)
1揽祥、權(quán)限申請(qǐng)
訪問(wèn)外部存儲(chǔ)上的文件,必須申請(qǐng) READ_EXTERNAL_STORAGE 或 WRITE_EXTERNAL_STORAGE 權(quán)限檩电。
<uses-permissionandroid:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
如果需要讀/寫(xiě)權(quán)限拄丰,只需要申請(qǐng) WRITE_EXTERNAL_STORAGE,內(nèi)包含讀取權(quán)限俐末。
2料按、檢查存儲(chǔ)介質(zhì)可用性
由于外部存儲(chǔ)介質(zhì)可能處于卸載、可讀或其他狀態(tài)卓箫,所以在使用之前一定要調(diào)用 getExternalStorageState() 檢查存儲(chǔ)介質(zhì)是否可用站绪,代碼如下:
publicbooleanisExternalStorageWritable(){
Stringstate=Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state)){
returntrue;
}
returnfalse;
}
3、保存公有文件
如果應(yīng)用保存的文件需要供給其他應(yīng)用或者用戶(hù)訪問(wèn)丽柿,那么文件應(yīng)該存放在公有目錄恢准,如果私有目錄文件或數(shù)據(jù)庫(kù)需要共享,那么要使用自定義 ContentProvider甫题。公有目錄在準(zhǔn)備知識(shí)中已經(jīng)介紹了馁筐,根據(jù)數(shù)據(jù)的類(lèi)型保存到對(duì)應(yīng)的目錄,比如圖片保存在 Pictures/坠非、 音樂(lè)保存在 Music/敏沉、下載文件保存在 Download/ 等,按類(lèi)別保存到對(duì)應(yīng)的目錄炎码,系統(tǒng)媒體掃描程序會(huì)將文件歸類(lèi)盟迟,而這些目錄獲取通過(guò)以下目錄
Environment.getExternalStoragePublicDirectory(Stringtype)
來(lái)看一段代碼,獲取圖片公有目錄潦闲,并在內(nèi)部創(chuàng)建 albumName 文件夾
publicFilegetAlbumStorageDir(StringalbumName{
Filefile=newFile(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES),albumName);if(!file.mkdirs()){Log.e(LOG_TAG,"創(chuàng)建失敗");
}
returnfile;
}
4攒菠、保存私有文件
調(diào)用 getExternalFilesDir(String type) 將數(shù)據(jù)保存在外部存儲(chǔ)的私有存儲(chǔ)目錄下。需要將文件保存至合適目錄歉闰,可以通過(guò) type 指定目錄類(lèi)型辖众,具體類(lèi)型參考準(zhǔn)備知識(shí)部分。
從 Android 4.4 開(kāi)始如果僅僅讀取或?qū)懭胨接形募途矗瑒t不需要文件讀寫(xiě)權(quán)限凹炸,如果需要兼容低版本,可以通過(guò)添加 maxSdkVersion 屬性來(lái)聲明昼弟,只在較低版本上使用權(quán)限啤它,來(lái)看代碼:
當(dāng)卸載應(yīng)用時(shí),此目錄下的所有文件將被清除。
5变骡、外部存儲(chǔ)空間上保存緩存文件
要將文件緩存在外部存儲(chǔ)上救欧,需要用 getExternalCacheDir() 訪問(wèn),該目錄是私有目錄锣光。同樣該目錄會(huì)隨著應(yīng)用卸載而清除,且清理緩存文件時(shí)也會(huì)清理該目錄铝耻。應(yīng)用提高 app 性能和穩(wěn)定性誊爹,應(yīng)當(dāng)自行維護(hù)緩存目錄的大小,而不能依賴(lài)系統(tǒng)瓢捉。這里建議使用 ContextCompat.getExternalCacheDir() 訪問(wèn)频丘,增強(qiáng)向下兼容性。
使用數(shù)據(jù)庫(kù)
Android 系統(tǒng)提供對(duì) SQLite 數(shù)據(jù)庫(kù)的完全支持泡态,在應(yīng)用開(kāi)發(fā)中搂漠,根據(jù)自己需求,使用數(shù)據(jù)庫(kù)某弦,比如需要存儲(chǔ)復(fù)雜關(guān)聯(lián)關(guān)系數(shù)據(jù)桐汤,存放安全數(shù)據(jù)等。
使用網(wǎng)絡(luò)
將數(shù)據(jù)保存在云端靶壮。
總結(jié):
如果敏感數(shù)據(jù)或者不被其他應(yīng)用訪問(wèn)的數(shù)據(jù)存放在內(nèi)部存儲(chǔ)私有目錄 怔毛,非隱私數(shù)據(jù)可存放在外部存儲(chǔ)私有目錄或者公有目錄下。
公有文件存放在外部存儲(chǔ) getExternalStoragePublicDirectory 目錄下腾降,不同的文件類(lèi)型通過(guò) type 指定存放到對(duì)應(yīng)的目錄拣度,好讓系統(tǒng)的媒體掃描程序可以在系統(tǒng)中正確地歸類(lèi)您的文件。
公有目錄文件的讀寫(xiě)操作需要申請(qǐng)文件讀寫(xiě)權(quán)限螃壤;自身應(yīng)用訪問(wèn)外部存儲(chǔ)私有目錄 Android 4.4 以及更高版本不需要申請(qǐng)文件讀寫(xiě)權(quán)限抗果,低于 4.4 需要申請(qǐng)權(quán)限;自身應(yīng)用訪問(wèn)內(nèi)部存儲(chǔ)私有目錄不需要申請(qǐng)文件讀寫(xiě)權(quán)限奸晴;訪問(wèn)其他應(yīng)用外部存儲(chǔ)私有目錄需要申請(qǐng)文件讀寫(xiě)權(quán)限冤馏。
系統(tǒng)清理緩存的時(shí)候,內(nèi)部存儲(chǔ)私有目錄 cache下的所有文件和外部存儲(chǔ)私有目錄 cache 下所有文件將被清除寄啼;系統(tǒng)清理數(shù)據(jù)的時(shí)候宿接,內(nèi)部存儲(chǔ)私有目錄和外部程序私有目錄下所有內(nèi)容將被清理。
使用外部存儲(chǔ)時(shí)要檢查外部存儲(chǔ)介質(zhì)是否存在辕录。