在android平臺中,數(shù)據(jù)存儲一共有5種方式:
- SharedPreference
- ** 文件**
- SQLite數(shù)據(jù)庫
- ContentProvider
- 網(wǎng)絡(luò)
接下來依次介紹一下各種存儲方式柱宦。
SharedPreferences
SharedPreference
可以用來保存任何原始數(shù)據(jù):布爾值踩身、浮點值别凹、整型值、長整型和字符串,它存儲的數(shù)據(jù)以鍵值對的形式挤牛,生成一個xml文件,存放在/data/data/<package name>/shared_prefs
路徑下种蘸。
獲取SharedPreferences
對象通常有兩種方法:
getSharedPreferences()
此方法包含另個參數(shù)墓赴,第一個是文件名,第二個是mode航瞭。采用該方法生成的SharedPreferences文件诫硕,是整個應(yīng)用所共享的,可以在同一應(yīng)用的任意Context下讀寫刊侯。它是屬于Context類的getPreferences()
此方法只有一個參數(shù)章办,mode。它所生成的文件滨彻,用包名+類名
的方式來命名藕届,比如應(yīng)用包為com.example.app
,生成該文件的類是位于preferences
包下的MyPreferenceActivity
類亭饵,那么它的路徑如下:
/data/data/com.example.app/shares_prefs/preferences.MyPreferenceActivity.xml
它適用于只在當(dāng)前Activity
調(diào)用的sharedPreferences
休偶,是屬于Activity類的。
除了以上兩種方法之外辜羊,還有一種方法:
PreferenceManager.getDefaultSharedPreferences(Context context);
這樣獲取到的對象是應(yīng)用默認(rèn)的Preference文件踏兜,它的名字是該應(yīng)用的完整包名+_preferences
。比如應(yīng)用包為com.example.app
八秃,生成該文件的類是位于preferences
包下的MyPreferenceActivity
類庇麦,那么它的路徑如下:
/data/data/com.example.app/shares_prefs/com.example.app_preferences.xml
。
SharedPreferences的mode參數(shù)
剛才提到的參數(shù)mode喜德,有以下值可選:
Context.MODE_PRIVATE
該SharedPreferences
數(shù)據(jù)只能被本應(yīng)用程序讀山橄、寫。Context.MODE_APPEND
寫入數(shù)據(jù)采用append
方式舍悯。Context.MODE_WORLD_READABLE
該SharedPreferences
數(shù)據(jù)能被其他應(yīng)用程序讀航棱,但不能寫。4.2之后已棄用萌衬。Context.MODE_WORLD_WRITEABLE
該SharedPreferences
數(shù)據(jù)能被其他應(yīng)用程序讀和寫饮醇。4.2之后已棄用。Context.MODE_MULTI_PROCESS
sdk2.3后添加的選項秕豫,當(dāng)多個進(jìn)程同時讀寫同一個SharedPreferences
時它會檢查文件是否修改朴艰。6.0中已棄用
所以观蓄,通常情況下我們選MODE_PRIVATE
就可以了,也可以直接寫0祠墅,就是MODE_PRIVATE
侮穿。只有在跨進(jìn)程訪問SharedPreferences
時,才會選用MODE_MULTI_PROCESS
毁嗦。其實MODE_PRIVATE
也可以跨進(jìn)程訪問亲茅,但是讀取到的數(shù)據(jù)是不會更新的,一直都是初始數(shù)據(jù)狗准。
在獲取到SharedPreferences
對象以后克锣,就可以修改存儲數(shù)據(jù)了。需要注意的是腔长,SharedPreferences
對象本身并不對數(shù)據(jù)進(jìn)行修改袭祟,而是通過Editor來進(jìn)行操作的,修改完成以后調(diào)用editor.commit
來提交捞附。下面看具體代碼:
SharedPreferences sp;
SharedPreferences preferences;
SharedPreferences defautSp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.data_storage);
sp=getSharedPreferences("preferences_1", MODE_PRIVATE);
preferences=getPreferences(MODE_PRIVATE);
defautSp=PreferenceManager.getDefaultSharedPreferences(this);
Editor editor = sp.edit();
editor.putString("name", "你大爺");
editor.commit();
//讀取數(shù)據(jù)榕酒,第二個參數(shù)是讀取失敗時返回的值
String name = sp.getString("name", "");
注意:SharedPreferences
文件默認(rèn)為private
模式,editor中的內(nèi)容就是文件中將要存儲的內(nèi)容故俐,新的editor提交以后,文件中存儲的就是剛提交的editor中的數(shù)據(jù)紊婉,之前的所有數(shù)據(jù)都會被覆蓋掉. 可以在創(chuàng)建對象時指定模式為APPEND
不同應(yīng)用之間訪問SharedPreference:
因為SharedPreferences
是與Context
相關(guān)的药版,想訪問其他應(yīng)用的SharedPreferences
,第一步應(yīng)該拿到目標(biāo)應(yīng)用的Context
喻犁,代碼如下:
Context trainContext=createPackageContext("com.example.app", Context.CONTEXT_IGNORE_SECURITY);
然后就可以用Context.getSharedPreferences("file_name",MODE_MULTI_PROCESS)
來獲取SharedPreferences
對象槽片。
還有關(guān)鍵的一步,跨應(yīng)用共享數(shù)據(jù)的時候肢础,需要在共享數(shù)據(jù)的應(yīng)用里中定義相同的SharedUserId
屬性:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.training"
android:versionCode="1"
android:versionName="1.0"
android:sharedUserId="com.share"
>
這樣还栓,就可以在不同的應(yīng)用中共享數(shù)據(jù)了。
除此之外传轰,還可以用文件的方式剩盒,直接通過路徑來讀取xml文件:
File xmlFile = new File(“/data/data/.../shared_prefs/config.xml”)
文件存儲
在Android中,可以使用下面兩種方法慨蛙,來存儲和讀取文件:
FileInputStream openFileInput(String name);
FileOutputStream openFileOutput(String name , int mode);
使用這種方式保存到內(nèi)部存儲的文件是應(yīng)用的私有文件辽聊,存儲路徑為/data/data/<package name>/files
目錄,如: /data/data/com.example.app/files/message.txt
,其他應(yīng)用是不能訪問這些數(shù)據(jù)的期贫。
示例代碼如下:
存儲:
try {
FileOutputStream fos = openFileOutput("file_1", MODE_PRIVATE);
fos.write("This is file storage.".getBytes());
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
讀取文件:
try {
FileInputStream fis = openFileInput("file_1");
StringBuilder sb = new StringBuilder();
int length=-1;
byte[] buffer = new byte[1024];
while ((length = fis.read(buffer)) != -1) {
//sb.append(new String(buffer,0,length);
sb.append(EncodingUtils.getString(buffer,0,length, "UTF-8"));
}
fis.close();
Log.d("Storage", "File content: "+sb.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
在輸出文件的時候跟匆,openFileOutput也有一個mode,官方文檔是這么說的:
MODE_PRIVATE
將會創(chuàng)建文件(或替換具有相同名稱的文件)通砍,并將其設(shè)為應(yīng)用的私有文件玛臂。 其他可用模式包括:MODE_APPEND、MODE_WORLD_READABLE、 MODE_WORLD_WRITEABLE
注:自 API 級別 17 以來迹冤,常量 MODE_WORLD_READABLE 和 MODE_WORLD_WRITEABLE 已被棄用讽营。從 Android N 開始,使用這些常量將會導(dǎo)致引發(fā) SecurityException叁巨。這意味著斑匪,面向 Android N 和更高版本的應(yīng)用無法按名稱共享私有文件,嘗試共享“file://”URI 將會導(dǎo)致引發(fā)FileUriExposedException锋勺。 如果您的應(yīng)用需要與其他應(yīng)用共享私有文件蚀瘸,則可以將 FileProvider
與 FLAG_GRANT_READ_URI_PERMISSION 配合使用。另請參閱共享文件庶橱。
Android的文件存儲系統(tǒng)
首先贮勃,可以看一下這篇博客,這里詳細(xì)的介紹了安卓的內(nèi)部存儲和外部存儲的區(qū)別。
內(nèi)部存儲
存放在/data/data/pacakge
路徑下苏章,SharedPreferences
寂嘉,SQLite數(shù)據(jù)庫
,還有文件存儲
枫绅,都是放在這個目錄下的泉孩,成為應(yīng)用的內(nèi)部存儲。對應(yīng)用的內(nèi)部存儲進(jìn)行操作并淋,除了上邊介紹的兩個方法之外寓搬,還有以下常用方法:
getFilesDir()
獲取在其中存儲內(nèi)部文件的文件系統(tǒng)目錄的絕對路徑。即:/data/data/pacakge/flies
getDir(String name, int mode)
在您的內(nèi)部存儲空間內(nèi)創(chuàng)建(或打開現(xiàn)有的)目錄县耽。如果沒有句喷,會創(chuàng)建一個app_name
文件夾,返回的路徑是/data/data/pacakge/app_name
deleteFile(String name)
刪除保存在內(nèi)部存儲(files文件夾)的文件。fileList()
返回應(yīng)用當(dāng)前保存的一系列文件(files文件夾下的文件列表)
除此之外兔毙,還有一個保存緩存文件的方法:
getCacheDir()
它表示您的應(yīng)用應(yīng)該將臨時緩存文件保存到的內(nèi)部目錄唾琼,獲取到的是/data/data/pacakge/cache
目錄.
關(guān)于緩存文件,Android是這么說的:
當(dāng)設(shè)備的內(nèi)部存儲空間不足時澎剥,Android 可能會刪除這些緩存文件以回收空間锡溯。 但您不應(yīng)該依賴系統(tǒng)來為您清理這些文件, 而應(yīng)該始終自行維護(hù)緩存文件哑姚,使其占用的空間保持在合理的限制范圍內(nèi)(例如 1 MB)趾唱。
內(nèi)部存儲的所有文件在用戶卸載應(yīng)用時,這些文件也會被移除蜻懦。
外部存儲
與內(nèi)部存儲相對的甜癞,外部存儲可以是SD卡,擴(kuò)展的u盤宛乃,系統(tǒng)自帶的內(nèi)部存儲卡等等念秧,它的特點是,所有的文件是全局都可以訪問的阅爽,而內(nèi)部存儲通常是應(yīng)用私有的(可以通過context來訪問)茬斧。
要操作外部存儲之前蜗搔,首先要獲得訪問權(quán)限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
如果需要讀取和寫入文件,則只需請求 WRITE_EXTERNAL_STORAGE權(quán)限,因為此權(quán)限也隱含了讀取權(quán)限要求。
Android中的外部存儲拂玻,又可以分為兩個部分,一是可以與其他應(yīng)用共享的公共文件宰译,比如 Music/
檐蚜、Pictures/
和 Ringtones/
等
另一部分則是私有文件,這里私有文件的定義不是說其他的應(yīng)用不可以訪問沿侈,而是對其他應(yīng)用沒有訪問價值闯第,應(yīng)用卸載之后,私有文件也會隨之刪除缀拭,而公共文件會被保留下來咳短。
- 公共文件:路徑是/storage/sdcard
常用方法:
Environment.getExternalStorageDirectory()
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM)//獲取系統(tǒng)的照片文件路徑
比如要在DCIM文件夾下創(chuàng)建一個新的文件夾
File newfile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), "myPicture");
if (!newfile.mkdirs()) {
Log.e("Storage", "Directory not created");
}
- 外部私有文件:路徑是/storage/sdcard/Android/data/packagename/files
外部私有文件的操作是屬于Context類的,主要有以下常用方法:
File getExternalFilesDir()
File[] getExternalFilesDirs()
File getExternalCacheDir()
File[] getExternalCacheDirs()
File[] getExternalMediaDirs()
例如蛛淋,要創(chuàng)建一個ext_private_file文件夾:
File newfile2 = new File(this.getExternalFilesDir("ext_private"), "myPicture");
if (!newfile2.mkdirs()) {
Log.e("Storage", "Directory not created");
}
這個文件存儲的位置并不是sd卡的根目錄下的ext_private
文件夾咙好,Android會為外部的私有存儲新建一個目錄,例如:/storage/sdcard/Android/data/<package_name>/files/
褐荷。其他的應(yīng)用也可以訪問這個目錄勾效,但是,存放在此處的內(nèi)容通常是對其他應(yīng)用沒有訪問價值诚卸。
與外部公共文件相比,私有文件在應(yīng)用卸載的時候绘迁,會隨之一起刪除合溺,而使用Environment
內(nèi)的操作方法創(chuàng)建的公共文件并不會隨之卸載。
在API19 Android4.4以后缀台,操作外部的私有存儲并不需要申請讀寫權(quán)限了棠赛。