前言
Android提供了多種選項(xiàng)來(lái)保存永久性應(yīng)用數(shù)據(jù)。用戶(hù)可以選擇的數(shù)據(jù)存儲(chǔ)選項(xiàng)有:共享首選項(xiàng)、內(nèi)部存儲(chǔ)、外部存儲(chǔ)、SQLite數(shù)據(jù)庫(kù)、網(wǎng)絡(luò)存儲(chǔ)。
文章開(kāi)始前用一張圖表示共享首選項(xiàng),內(nèi)部存儲(chǔ),外部存儲(chǔ)

一、使用共享首選項(xiàng)
1、關(guān)鍵類(lèi):SharedPreferences類(lèi)
可以使用ShatedPreferences來(lái)保存任何原始數(shù)據(jù):布爾值、浮點(diǎn)值、整型值、長(zhǎng)整型、字符串。
這些數(shù)據(jù)將會(huì)跨多個(gè)用戶(hù)會(huì)話永久保留。
2、介紹如何獲得SharedPreferences對(duì)象
2.1 、(1)getSharedPreferences(String name,int mode);
通過(guò)Context調(diào)用,參數(shù)一:首選項(xiàng)文件名,如果此名稱(chēng)的首選項(xiàng)文件不存在,那么會(huì)在再檢索編輯器SharedPreferences.edit()并提交更改(Editor.commit())時(shí)創(chuàng)建這個(gè)文件。
參數(shù)二默認(rèn)填寫(xiě)0或者是MODE_PRIVATE(創(chuàng)建的文件只能由調(diào)用應(yīng)用程序訪問(wèn)),別的模式MODE_WORLD_READABLE(創(chuàng)建全都可讀文件,容易造成安全漏洞,已在17棄用)與MODE_WORLD_WRITEABLE(創(chuàng)建全部課讀寫(xiě)文件,容易造成安全漏洞,已在17棄用)與MODE_MULTI_PROCESS(在某些版本的Android中無(wú)法可靠運(yùn)行,不提供任何機(jī)制來(lái)協(xié)調(diào)跨進(jìn)程的并發(fā)修改,已在23棄用)
2.2 、getPreferences(int mode);
在Activity中調(diào)用,參數(shù)參照上面,一般用0就可以。
調(diào)用SharedPreferences.edit()方法并最后提交更改(Editor.commit())時(shí)候創(chuàng)建文件,文件名就是以當(dāng)前Activity的類(lèi)名,比較簡(jiǎn)單的基于當(dāng)前Activity創(chuàng)建其相應(yīng)的SharedPreferences文件。
3、詳細(xì)介紹
其應(yīng)該是一個(gè)interface,放在android.content.SharedPreferences包下。
其嵌套了接口Editor與接口 OnShatedPreferenceChangeListener。
通過(guò)SharedPreferences對(duì)象可以調(diào)用如下方法:
3.1 ->>>
contains(String key)
返回值:boolean
檢驗(yàn)當(dāng)前SharedPreferences文件中是否包含某個(gè)key
3.2->>>
getAll()
返回值:Map<String,?>
返回當(dāng)前SharedPreferences文件中所有的key以及相應(yīng)的value值
示例:
Map<String,?> map = mSharedPreferences.getAll();
這樣此SharedPreferences中所有的值都在Map集合中
3.3->>>
getBoolean(String key,boolean defValue)
返回值:boolean
得到此SharedPreferences中boolean類(lèi)型的Key對(duì)應(yīng)的value,其中參數(shù)二表示默認(rèn)值。
需要說(shuō)明的是,如果此key 對(duì)應(yīng)的值不是布爾值,那么就會(huì)拋出ClassCastException異常,如果不處理,程序會(huì)崩潰,所以在使用查詢(xún)的時(shí)候:
示例
try {
int i = mSharedPreferences.getInt("age", 1);
mTextViewa.setText("" + i);
} catch (ClassCastException e) {
mTextViewa.setText("出現(xiàn)異常了");
}
3.4->>>
getFloat(String key,float defValue)
返回值:float
與getBoolean方法一樣,不同的是得到的是float值,針對(duì)的是float類(lèi)型的數(shù)據(jù)查詢(xún),如果傳入的Key對(duì)應(yīng)的值不是vlaue,那么也會(huì)拋出ClassCastException異常。
3.5->>>
getInt(String key,int defValue)
返回值:int
與getBoolean方法一樣,不同的是得到的是int值,如果傳入的key查詢(xún)出來(lái)不是int類(lèi)型的,那么也會(huì)拋出ClassCastException異常。
3.6->>>
getLong(String key ,long defValue)
返回值:long
與getBoolean方法一樣,不同的是得到的是long值,如果傳入的key查詢(xún)出來(lái)不是int類(lèi)型的,那么也會(huì)拋出ClassCastException異常。
3.7->>>
getString(String key,String defValue)
與getBoolean方法一樣,不同的是得到的是String值,如果傳入的key查詢(xún)出來(lái)不是int類(lèi)型的,那么也會(huì)拋出ClassCastException異常,defVlue也可以是null
3.8->>>
getStringSet(String key,Set<String> defValues)
返回值:Set<String>
defValues可以是null,也會(huì)拋出ClassCastException,另外,存入的是Set<String>,也就是一組String數(shù)據(jù)。
3.9->>>
registerOnSharedPreferenceChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)
警告:首選項(xiàng)管理器當(dāng)前不存儲(chǔ)對(duì)偵聽(tīng)器的強(qiáng)引用。 您必須存儲(chǔ)對(duì)偵聽(tīng)器的強(qiáng)引用,否則它將容易被垃圾收集。 只要您需要偵聽(tīng)器
,我們建議您在對(duì)象的實(shí)例數(shù)據(jù)中保留對(duì)偵聽(tīng)器的引用。
此監(jiān)聽(tīng)發(fā)生在此SharedPreferences文件內(nèi)容發(fā)生更改的時(shí)候。
3.10->>>
unregisterOnSharedPreferencesChangeListener(SharedPreferences.OnSharedPreferenceChangeListener listener)
取消監(jiān)聽(tīng)
3.11->>>
edit()
返回值:SharedPreferences.Editor
具體作用參照下面Editor中方法具體介紹。
4介紹SharedPreferences中的Editor中方法
操作當(dāng)前SharedPreferences中文件中的值,只有通過(guò)commit或者apply之后,才會(huì)建立相應(yīng)的SharedPreferences文件與完成相應(yīng)的修改。
4.1 ->>>
putBoolean(String key,boolean value)
返回值:SharedPreferences.Editor
寫(xiě)入到當(dāng)前SharedPreferences文件中一對(duì)key-value或者是修改已經(jīng)存在key對(duì)應(yīng)的value的值。
4.2 ->>>
putFloat(String key,float value)
返回值:SharedPreferences.Editor
寫(xiě)入到當(dāng)前SharedPreferences文件中一對(duì)key-value或者是修改已經(jīng)存在key對(duì)應(yīng)的value的值。
4.3 ->>>
putInt(String key,int value)
返回值:SharedPreferences.Editor
寫(xiě)入到當(dāng)前SharedPreferences文件中一對(duì)key-value或者是修改已經(jīng)存在key對(duì)應(yīng)的value的值。
4.4 ->>>
putLong(String key,long value)
返回值:SharedPreferences.Editor
寫(xiě)入到當(dāng)前SharedPreferences文件中一對(duì)key-value或者是修改已經(jīng)存在key對(duì)應(yīng)的value的值。
4.5 ->>>
putString(String key,String value)
返回值:SharedPreferences.Editor
寫(xiě)入到當(dāng)前SharedPreferences文件中一對(duì)key-value或者是修改已經(jīng)存在key對(duì)應(yīng)的value的值。
4.6 ->>>
putStringSet(String key,Set<String> values)
返回值:SharedPreferences.Editor
寫(xiě)入到當(dāng)前SharedPreferences文件中一對(duì)key-value或者是修改已經(jīng)存在key對(duì)應(yīng)的value的值。
對(duì)此參數(shù)傳遞null等價(jià)于使用此鍵調(diào)用remove(String)
4.7 ->>>
remove(String key)
返回值:SharedPreferences.Editor
移除當(dāng)前SharedPreferences中某個(gè)Key以及其所代表的值
4.8 ->>>
clear()
返回值:SharedPreferences.Editor
移除所有的key以及value從當(dāng)前SharedPreferences文件中。
4.9 ->>>
commit()
返回值:boolean
如果新值成功寫(xiě)入當(dāng)前SharedPreferences,則返回true;
會(huì)自動(dòng)執(zhí)行請(qǐng)求的參數(shù),替換SharedPreferences中的修改,如果沒(méi)有的話,就會(huì)創(chuàng)建此文件
當(dāng)兩個(gè)編輯器同時(shí)修改時(shí),最后一個(gè)調(diào)用commit的成功
如果你不關(guān)心返回值,并且你在應(yīng)用程序的主線程中使用它,請(qǐng)使用apply();
4.10 ->>>
apply()
返回值:void
1、如果先后apply()了幾次,那么會(huì)以最后一次apply()的為準(zhǔn)。
2、commit()是把內(nèi)容同步提交到硬盤(pán)的。而apply()先立即把修改提交到內(nèi)存,然后開(kāi)啟一個(gè)異步的線程提交到硬盤(pán),
并且如果提交失敗,你不會(huì)收到任何通知。
也就是說(shuō),commit有返回值,apply沒(méi)有返回值,commit寫(xiě)入文件操作是在主線程中,會(huì)消耗資源,apply寫(xiě)入文件的操作是異步的,
會(huì)把Runnable放到線程池中執(zhí)行
3、如果當(dāng)一個(gè)apply()的異步提交還在進(jìn)行的時(shí)候,執(zhí)行commit()操作,那么commit()是會(huì)阻塞的。
而如果commit()的時(shí)候,前面的commit()還未結(jié)束,這個(gè)commit()還是會(huì)阻塞的。(所以引起commit阻塞會(huì)有這兩種原因)
4、由于SharePreferences在一個(gè)程序中的實(shí)例一般都是單例的,所以如果你不是很在意返回值的話,你使用apply()代替commit()是無(wú)所謂的。
5、SP例子
(1)初始一個(gè)應(yīng)用在data/data/應(yīng)用包名下:

當(dāng)你使用了SharedPreferences時(shí)候
public static final String FILE_NAME = "MySharedPreferences";
mSharedPreferences = getSharedPreferences(FILE_NAME, 0);
//執(zhí)行完上述話,會(huì)在應(yīng)用程序中建立shared_prefs文件夾,里面將要存放sharedPreferences文件,但是目前沒(méi)有內(nèi)容
(2)當(dāng)你完成一些查詢(xún)操作,但是沒(méi)有完成使用Editor
mSharedPreferences = getSharedPreferences(FILE_NAME, 0);
String name = mSharedPreferences.getString("name","xlj");
//也沒(méi)有在shared_prefs文件夾下建立相應(yīng)的FILE_NAME文件,另外這樣用也不會(huì)報(bào)錯(cuò),返回name = xlj
(3)通過(guò)操作Editor
mSharedPreferences = getSharedPreferences(FILE_NAME, 0);
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString("name", "xljs");
editor.commit();

(1)演示第二種得到SharedPerferences方法:
mSharedPreferences = getPreferences(0);
SharedPreferences.Editor editor = mSharedPreferences.edit();
editor.putString("age", "10");
editor.putBoolean("is", true);
editor.commit();
Map<String,?> map = mSharedPreferences.getAll();
mTextViewa.setText(map.toString());
try {
int i = mSharedPreferences.getInt("age", 1);
mTextViewa.setText("" + i);
} catch (ClassCastException e) {
mTextViewa.setText("出現(xiàn)異常了");
}
(2)當(dāng)前Activity名字:SharedPActivity

在手機(jī)上使用應(yīng)用的內(nèi)部存儲(chǔ)
直接在設(shè)備的內(nèi)部存儲(chǔ)中保存文件。默認(rèn)情況下,保存到內(nèi)部存儲(chǔ)的文件是應(yīng)用的私有文件,其他應(yīng)用(和用戶(hù))都不能訪問(wèn)這些文件。當(dāng)用戶(hù)卸載應(yīng)用的時(shí)候,這些文件也會(huì)被移除。并且這些文件理論上是不可見(jiàn)的
簡(jiǎn)單來(lái)講,就是給我們自己的應(yīng)用,在內(nèi)部存儲(chǔ)分配的空間,默認(rèn)的有files文件夾、cache文件夾、
(其實(shí)共享首選項(xiàng)也是提供的默認(rèn)的shared_prefs文件夾)
當(dāng)然了,用戶(hù)也可以不用這些已經(jīng)提供的files 與 cache文件夾,自己建立自己的的文件夾,并放文件.
一、讀寫(xiě)files文件夾(根文件夾)下文件
1、openFileOutput()方法
屬于android.content.Context;
返回值:FileOutputStram一個(gè)文件輸出流
參數(shù)一:name,你要打開(kāi)的文件的名字,這里的name只能是名字,不能使用"/name"此類(lèi)的。
參數(shù)二:MODE_PRIVATE,別的模式處于安全都摒棄了
不同于常見(jiàn)getxxx方法,字面翻譯就是:打開(kāi)files文件夾下某個(gè)文件的輸出流
簡(jiǎn)單的方式得到一個(gè)文件輸出流
1.1例子
初始默認(rèn)的應(yīng)用程序內(nèi)部存儲(chǔ)如下圖:

shared_prefs文件夾是因?yàn)椴僮鬟^(guò)SharedPreferences才有的,默認(rèn)的初始就有一個(gè)空的cache文件夾。
private String FILE_NAME = "hello_file";
private String FILE_NAME_NEW = "test.txt";
String string = "怎么都是寫(xiě)不會(huì)的啊";
try {
FileOutputStream fileOutputStream = openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
fileOutputStream.write(string.getBytes());
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
mTextView2.setText("出現(xiàn)文件找不到異常");
} catch (IOException e) {
e.printStackTrace();
mTextView2.setText("出現(xiàn)了IO異常");
}
結(jié)果如圖:

出現(xiàn)了files文件夾以及相應(yīng)的文件。
try {
FileOutputStream fileOutputStream = openFileOutput(FILE_NAME_NEW, Context.MODE_PRIVATE);
fileOutputStream.write(string.getBytes());
fileOutputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
mTextView2.setText("出現(xiàn)文件找不到異常");
} catch (IOException e) {
e.printStackTrace();
mTextView2.setText("出現(xiàn)了IO異常");
}
結(jié)果:

如果給文件名字帶上具體的文件格式,也沒(méi)有什么影響。
說(shuō)明:
自Api17以來(lái),常量MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE已經(jīng)被棄用。
從Android N開(kāi)始,使用這些常量會(huì)引發(fā)securityException。
這意味著,面向Android N 和更高版本的應(yīng)用無(wú)法按名稱(chēng)共享私有文件,嘗試共享file://URL將會(huì)導(dǎo)致引發(fā)FileUriExposedException。
如果應(yīng)用需要與其他應(yīng)用共享私有文件,則可以將FileProvider與FLAG_GRANT_READ_URI_PERMISSION配合使用。
2、openFileInput
屬于android.content.Context;
參數(shù)一:傳入你想讀取的文件的名字,這里的name只能是名字,不能使用"/name"此類(lèi)的。
返回值:返回一個(gè)FileInputStream。
不用于常見(jiàn)的getxxx方法,字面翻譯:打開(kāi)文件輸入流
方便直接得到一個(gè)流
2.1例子
try {
FileInputStream fileInputStream = openFileInput(FILE_NAME);
byte[] buf = new byte[1024];
int hasRead = 0;
StringBuffer sb = new StringBuffer("");
//讀取文件部分
while((hasRead = fileInputStream.read(buf))>0){
sb.append(new String(buf,0,hasRead));
}
fileInputStream.close();
mTextView.setText(sb.toString());
} catch (FileNotFoundException e) {
e.printStackTrace();
mTextView.setText("出現(xiàn)文件找不到異常了");
} catch (IOException e) {
e.printStackTrace();
mTextView.setText("出現(xiàn)了IO異常了");
}
}

通過(guò)動(dòng)圖可以看出來(lái),是可以的讀取出來(lái)數(shù)據(jù)。
另外需要注意的是,如果你開(kāi)始讀的文件不存在就會(huì)報(bào)FileNotFoundException異常,當(dāng)時(shí)會(huì)建立files文件夾,如果此文件夾不存在的話。
3、getFilesDir()
也是在android.content.context中提供的屬性
執(zhí)行此方法的到的是:
如果不想用openFileInput與openFileOutput兩個(gè)方法,想使用get系列的方法也是可以的.
直接得到的是文件的路徑,而不是得到一個(gè)流,這樣可以自己用.
/data/user/0/example.xlj.savecundemo/files
應(yīng)用程序內(nèi)部存儲(chǔ)空間中files的目錄
獲取在其中存儲(chǔ)內(nèi)部文件的文件系統(tǒng)目錄的絕對(duì)路徑。
例子
這只是一種簡(jiǎn)單的例子,延時(shí)了某一個(gè)用法
File file = new File(getFilesDir(),"infos.txt");//返回值是File對(duì)象
try {
FileOutputStream outputStream = new FileOutputStream(file);
String s = "這是一個(gè)測(cè)試的例子,往info里面寫(xiě)入數(shù)據(jù)";
outputStream.write(s.getBytes());
outputStream.close();
mTextView4.setText("文件寫(xiě)入成功");
} catch (FileNotFoundException e) {
e.printStackTrace();
mTextView4.setText("文件未找到異常");
} catch (IOException e) {
e.printStackTrace();
mTextView4.setText("出現(xiàn)了IO異常");
}
結(jié)果如圖:

也是在files文件夾下創(chuàng)建了infos.txt文件。完成了存儲(chǔ)
3其他的常用方法,針對(duì)于自己應(yīng)用內(nèi)部存儲(chǔ)中 files (強(qiáng)調(diào)的是files)文件夾下的操作
3.1fileList()
返回保存在內(nèi)部存儲(chǔ)空間一系列文件。
String [] list = fileList();
for (int i = 0; i < list.length; i++) {
Log.d("xljxlj",list[i]);
}
得到的結(jié)果如下:
05-05 03:43:48.829 7396-7396/example.xlj.savecundemo D/xljxlj: hello_file
05-05 03:43:48.829 7396-7396/example.xlj.savecundemo D/xljxlj: test.txt
05-05 03:43:48.829 7396-7396/example.xlj.savecundemo D/xljxlj: infos.txt
3.2deleteFile(String name)
刪除保存在內(nèi)部存儲(chǔ)的文件,其返回值是一個(gè)Boolean,表示是否刪除成功。
這里的name只能是名字,不能使用"/name"此類(lèi)的。
說(shuō)明
如果在一讀一寫(xiě)的操作中,出現(xiàn)了亂碼,那么上面的代碼需要做如下調(diào)整
寫(xiě)入的時(shí)候
try {
FileOutputStream fileOutputStream = GudleActivity.this.openFileOutput(ApiTools.MAIN_INFO_FILES, Context.MODE_PRIVATE);
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream,"UTF-8");
outputStreamWriter.write(response.toString());
outputStreamWriter.flush();
outputStreamWriter.close();
} catch (IOException e) {
//出現(xiàn)異常緩存失敗
e.printStackTrace();
}
讀取的時(shí)候
try {
FileInputStream fileInputStream = openFileInput(ApiTools.MAIN_INFO_FILES);
InputStreamReader reader = new InputStreamReader(fileInputStream,"UTF-8"); //最后的"GBK"根據(jù)文件屬性而定,如果不行,改成"UTF-8"試試
BufferedReader br = new BufferedReader(reader);
String line;
while ((line = br.readLine()) != null) {
LogUtils.debugInfo("maininfo","得到數(shù)據(jù):"+line);
}
br.close();
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
二、讀寫(xiě)cache文件夾中文件
如果您想要緩存一些數(shù)據(jù),而不是永久的存儲(chǔ)這些數(shù)據(jù),可以考慮Cache文件夾下存儲(chǔ)。
當(dāng)設(shè)備的內(nèi)部存儲(chǔ)空間不足的時(shí)候,Android可能會(huì)刪除這些緩存文件以回收空間。但您不應(yīng)該依賴(lài)系統(tǒng)來(lái)為你清理這些文件,而應(yīng)該是中自行維護(hù)緩存文件,使其占用的控件保持在合理的限制范圍內(nèi)例如1MB,當(dāng)用戶(hù)卸載您的應(yīng)用的時(shí)候,這些文件也會(huì)被移除。
1、通過(guò)getCacheDir()
例子
File file = new File(getCacheDir(),"infos.txt"); //返回值是File對(duì)象
try {
FileInputStream fileInputStream = new FileInputStream(file);
byte[] bytes = new byte[1024];
int hascode = 0;
StringBuffer stringBuffer = new StringBuffer("");
while ((hascode = fileInputStream.read(bytes))>0){
stringBuffer.append(new String(bytes,0,hascode));
}
mTextView5.setText(stringBuffer.toString());
fileInputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
mTextView5.setText("出現(xiàn)了文件未找到異常");
} catch (IOException e) {
e.printStackTrace();
mTextView5.setText("出現(xiàn)了IO異常了");
}

忽略info,這是之前做的測(cè)試,目前只貼了一個(gè)infos.txt的代碼
2、讀寫(xiě)內(nèi)存存儲(chǔ)空間中自定義文件夾中文件
如果你不想放在files與cache文件夾下,可以通過(guò)getDir()方法,其返回值是:File
如果執(zhí)行g(shù)etDir("test",MODE_PRIVATE)
這樣在執(zhí)行代碼,會(huì)先建立這個(gè)文件夾.,不過(guò)都會(huì)自動(dòng)添加app_前綴,這個(gè)不需要自己去考慮
/data/user/0/example.xlj.savecundemo/app_test
如果存在則返回先關(guān)文件夾的路徑,如果沒(méi)有的話就創(chuàng)建并且返回相關(guān)的FIle。
那么相關(guān)的操作就類(lèi)似了,
File file = new File(getDir("test",MODE_PRIVATE),"who.txt");
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
String ss = "自己新建立了一個(gè)文件夾";
fileOutputStream.write(ss.getBytes());
fileOutputStream.close();
Toast.makeText(FileActivity.this,"寫(xiě)入成功",Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}

如圖中app_test就是通過(guò)執(zhí)行上述代碼完成的。這里只演示了文件寫(xiě)入,對(duì)于讀取文件通上述,不在過(guò)多代碼演示。
讀取資源文件(不屬于內(nèi)部存儲(chǔ)內(nèi)容)這部分是引申
如果在編譯時(shí)想要保存應(yīng)用中的靜態(tài)文件,請(qǐng)?jiān)陧?xiàng)目的res/raw/目錄中保存該文件??梢酝ㄟ^(guò)openRawResource()打開(kāi)該資源文件并傳遞R.raw.xxx資源ID,此方法返回一個(gè)InputStream(注意不是FileInputStream),您可以使用該流傳輸讀取文件(但是不能寫(xiě)入到原始文件,只能讀取)
也是得到一個(gè)資源文件流,注意不是應(yīng)用存儲(chǔ)內(nèi)部存儲(chǔ)中
下面通過(guò)例子進(jìn)行演示:
準(zhǔn)備文件:

演示讀取activity.file.xml文件
try {
InputStream fileInputStream = FileActivity.this.getResources().openRawResource(R.raw.activity_file);
byte[] buf = new byte[1024];
int hasRead = 0;
StringBuffer sb = new StringBuffer("");
//讀取文件部分
while((hasRead = fileInputStream.read(buf))>0){
sb.append(new String(buf,0,hasRead));
}
fileInputStream.close();
mTextView3.setText(sb.toString());
} catch (Resources.NotFoundException e) {
e.printStackTrace();
mTextView3.setText("出現(xiàn)文件找不到異常了");
} catch (IOException e) {
e.printStackTrace();
mTextView3.setText("出現(xiàn)了IO異常了");
}

演示如何讀取一個(gè)圖片
//演示怎么讀取一張圖片
InputStream inputStream = getResources().openRawResource(R.raw.my_my_name);
//方式一
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
mImageView.setImageBitmap(bitmap);
//方式二
BitmapDrawable bitmapDrawable = new BitmapDrawable(inputStream);
Bitmap bitmap = bitmapDrawable.getBitmap();
mImageView.setImageBitmap(bitmap);
注意:如果出現(xiàn)了亂碼,建議首先檢查源文件,也就是raw目錄下的文件是否是亂碼。
使用手機(jī)的外部存儲(chǔ)
每個(gè)兼容Android的設(shè)備都支持可用于保存文件的共享“外部存儲(chǔ)”。該存儲(chǔ)可能是可移除的存儲(chǔ)介質(zhì)(如SD卡,次要卷),也可能是不可移除的存儲(chǔ)(主要卷)?,F(xiàn)在大部分手機(jī),都自帶不可移除的存儲(chǔ).
保存到外部存儲(chǔ)的文件,是全局可讀的,用戶(hù)可以通過(guò)USB鏈接上進(jìn)行修改.
共享,意味著所有的應(yīng)用都可以使用,并不是前面提到的每個(gè)應(yīng)用中的內(nèi)部存儲(chǔ).
簡(jiǎn)單來(lái)講,外部存儲(chǔ)其實(shí)分為了兩種文件類(lèi)型,一種是公共的存儲(chǔ)文件夾,一種是給具體應(yīng)用的存儲(chǔ)文件夾(也分為file 與 cache )
區(qū)別:這部分外部存儲(chǔ)的就是getExtralxxx開(kāi)頭的了,表明是外部存儲(chǔ).
Ram:手機(jī)的運(yùn)行內(nèi)存。
Rom:手機(jī)內(nèi)存,表現(xiàn)為內(nèi)部存儲(chǔ)空間,可以理解為電腦本身的硬盤(pán)。
SD:外部存儲(chǔ)空間,可以理解為電腦的移動(dòng)硬盤(pán)。
其實(shí)外部存儲(chǔ)系統(tǒng)給開(kāi)發(fā)者使用的地方可以分為公共文件夾與應(yīng)用私有文件夾區(qū)域:

一般來(lái)講就是在Storage/sdcard目錄下,如圖所示,DCIM、Download、Movies等等都是屬于公共文件夾,這部分文件夾對(duì)于當(dāng)前手機(jī)上所有的應(yīng)用都是公開(kāi)的。Android/data目錄下,有一個(gè)個(gè)以應(yīng)用名字命名的文件夾,里面可以存放當(dāng)前應(yīng)用的私有文件與緩存。
1、檢查介質(zhì)可用性
在使用外部存儲(chǔ)執(zhí)行任何工作之前,應(yīng)始終調(diào)用Environment.getExternalStorageState()方法以檢查介質(zhì)是否可用,介質(zhì)可能處于缺失、只讀或者其他狀態(tài)。
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
關(guān)于state可能值介紹:
MEDIA_UNKNOWN: 未知存儲(chǔ)狀態(tài),例如路徑未被已知存儲(chǔ)介質(zhì)支持時(shí)。
MEDIA_REMOVED: 存儲(chǔ)介質(zhì)不存在的存儲(chǔ)狀態(tài)。
MEDIA_UNMOUNTED: 存儲(chǔ)狀態(tài),如果介質(zhì)存在但未安裝。
MEDIA_CHECKING: 如果介質(zhì)存在并正在進(jìn)行磁盤(pán)檢查,則為存儲(chǔ)狀態(tài)。
MEDIA_NOFS: 存儲(chǔ)狀態(tài),如果介質(zhì)存在但空白或正在使用不受支持的文件系統(tǒng)。
MEDIA_MOUNTED: 存儲(chǔ)狀態(tài),如果介質(zhì)存在并且以讀/寫(xiě)訪問(wèn)的方式安裝在其安裝點(diǎn)。
MEDIA_MOUNTED_READ_ONLY: 存儲(chǔ)狀態(tài),如果介質(zhì)存在并且以只讀訪問(wèn)權(quán)限掛載到它的掛載點(diǎn)。
MEDIA_SHARED: 存儲(chǔ)狀態(tài),如果介質(zhì)未安裝,并通過(guò)USB海量存儲(chǔ)共享。
MEDIA_BAD_REMOVAL: 存儲(chǔ)狀態(tài),如果介質(zhì)在卸載之前被刪除。
MEDIA_UNMOUNTABLE: 存儲(chǔ)狀態(tài),如果介質(zhì)存在但無(wú)法安裝。 通常,如果介質(zhì)上的文件系統(tǒng)損壞,就會(huì)發(fā)生這種情況。
MEDIA_EJECTING: 存儲(chǔ)狀態(tài),如果媒體正在被彈出的過(guò)程中。
getExternalStorageState()方法將會(huì)返回可能需要檢查的其他狀態(tài),當(dāng)應(yīng)用需要訪問(wèn)介質(zhì)時(shí),可以使用這些狀態(tài)向用戶(hù)通知更多信息。
更多的關(guān)于Environment的使用介紹;
2、檢查權(quán)限
<user-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<user-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
兩點(diǎn)說(shuō)明:
(1)android 6.0提出了運(yùn)行時(shí)權(quán)限,需要開(kāi)發(fā)過(guò)程中注意,可以參考文章
(2)從Android4.4開(kāi)始,如果應(yīng)用僅僅讀取或者寫(xiě)入應(yīng)用的私有文件,則不需要這些權(quán)限,只有使用外部存儲(chǔ)的公共文件夾時(shí)需要。
3、在外部存儲(chǔ)公共文件位置存儲(chǔ)文件。
一般而言,應(yīng)該將用戶(hù)可通過(guò)您的應(yīng)用獲取的新文件保存到設(shè)備上的“公共”位置,以便其他應(yīng)用能夠在其中訪問(wèn)這些文件,并且用戶(hù)也能輕松地從該設(shè)備復(fù)制這些文件。 執(zhí)行此操作時(shí),應(yīng)使用共享的公共目錄之一,例如 Music/、Pictures/ 和 Ringtones/ 等。。
4、getExternalStoragePublicDirectory()方法,可與其他應(yīng)用共享
返回值:File
參數(shù):type
type可以有如下幾種選擇,其表示頂級(jí)公共目錄,當(dāng)做是標(biāo)準(zhǔn)目錄,卻沒(méi)有強(qiáng)制選擇使用相應(yīng)的:
DIRECTORY_ALARMS:用于放置任何音頻文件的標(biāo)準(zhǔn)目錄,該文件應(yīng)位于用戶(hù)可以選擇的鬧鈴文件列表(而不是普通音樂(lè)),的特定音頻文件。
DIRECTORY_DCIM:將設(shè)備安裝為相機(jī)時(shí)傳統(tǒng)照片和視頻位置。
DIRECTORY_DOCUMENTS:放置用戶(hù)創(chuàng)建的文檔的標(biāo)準(zhǔn)目錄。
DIRECTORY_DOWNLOADS:用于放置用戶(hù)下載文件的標(biāo)準(zhǔn)目錄,這是頂級(jí)公共目錄的約定。
DIRECTORY_MOVIES:用戶(hù)放置用戶(hù)電影的標(biāo)準(zhǔn)目錄,但是媒體掃描器會(huì)在任何目錄中查找和收集電影。
DIRECTORY_MUSIC:用于放置任何音頻文件的標(biāo)準(zhǔn)目錄。
DIRECTORY_NOTIFICATIONS:放置任何音頻文件的標(biāo)準(zhǔn)目錄,一般是用戶(hù)可以選擇的通知列表(而不是普通音樂(lè))
DIRECTORY_PICIURES:放置可供用戶(hù)使用的圖片的標(biāo)準(zhǔn)目錄。但是媒體掃描器將在任何目錄中查找和收集圖片。
DIRECTORY_PODCASTS:放置任何音頻的標(biāo)準(zhǔn)目錄,是可供選擇的播客列表中(而不是普通音樂(lè))。
DIRECTORY_RINGTONES:用于放置任何音頻的標(biāo)準(zhǔn)目錄,該文件可供用戶(hù)選擇鈴聲列表。
Google官方給出的例子:
void createExternalStoragePublicPicture() {
//創(chuàng)建了一個(gè)公共的放置圖片的路徑。
// Context.getExternalMediaDir() ,下面會(huì)進(jìn)行解釋
//上述方法的路徑:/storage/sdcard/Android/media/example.xlj.savecundemo
File path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
//在5.1上測(cè)試:/storage/sdcard/Pictures
//在7.0上測(cè)試:/storage/emulated/0/Pictures
File file = new File(path, "DemoPicture.jpg");
//在5.1上測(cè)試: /storage/sdcard/Pictures/DemoPicture.jpg
//在7.0上測(cè)試;/storage/emulated/0/Pictures/DemoPicture.jpg
try {
// Make sure the Pictures directory exists.確保文件夾存在,下面的方法表示創(chuàng)建相應(yīng)的文件夾。具體的文件就要靠流的操作來(lái)完成了。
path.mkdirs();
// Very simple code to copy a picture from the application's
// resource into the external file. Note that this code does
// no error checking, and assumes the picture is small (does not
// try to copy it in chunks). Note that if external storage is
// not currently mounted this will silently fail.
InputStream is = getResources().openRawResource(R.drawable.balloons);
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
// Tell the media scanner about the new file so that it is
// immediately available to the user.
//告訴媒體掃描器有關(guān)新文件的信息,立即告訴用戶(hù)。
//下面代碼表示演示了手機(jī)多媒體掃描的流程。
MediaScannerConnection.scanFile(this,
new String[] { file.toString() }, null,
new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
Log.i("ExternalStorage", "Scanned " + path + ":");
Log.i("ExternalStorage", "-> uri=" + uri);
}
});
} catch (IOException e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing " + file, e);
}
}
void deleteExternalStoragePublicPicture() {
// Create a path where we will place our picture in the user's
// public pictures directory and delete the file. If external
// storage is not currently mounted this will fail.
File path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File file = new File(path, "DemoPicture.jpg");
file.delete();
}
boolean hasExternalStoragePublicPicture() {
// Create a path where we will place our picture in the user's
// public pictures directory and check if the file exists. If
// external storage is not currently mounted this will think the
// picture doesn't exist.
File path = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
File file = new File(path, "DemoPicture.jpg");
return file.exists();
}
例子
//檢查設(shè)備介質(zhì)是否可以使用
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
先檢查設(shè)備介質(zhì)是否可用:
if (isExternalStorageWritable()) {
//這是使用的運(yùn)行時(shí)權(quán)限一個(gè)注解方式動(dòng)態(tài)申請(qǐng)權(quán)限
SDTestActivityPermissionsDispatcher.saveFileOneWithCheck(SDTestActivity.this);
} else {
mTextView1.setText("設(shè)備不可以用");
}
設(shè)備可用,執(zhí)行相應(yīng)的方法:
//保存可以與其他應(yīng)用共享的文件
@NeedsPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)
public void saveFileOne() {
//保在下載文件夾中
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "testwenjian");
/**
* File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),"testwenjian");
* 5.1:/storage/sdcard/Download/testwenjian
* 7.0:/storage/emulated/0/Download/testwenjian
* 不管是file.mkdir還是file.mkdirs都是創(chuàng)建目錄的,不是創(chuàng)建新的文件
* 創(chuàng)建了一次新的之后,表示已經(jīng)存在了,那么就不會(huì)在創(chuàng)建了,會(huì)返回一個(gè)false,表示文件夾未創(chuàng)建成功,但是實(shí)際上文件已經(jīng)存在了。
*具體效果如下圖一
*/
if (file.mkdir()) {
//表示文件創(chuàng)建成功了
mTextView1.setText("文件夾創(chuàng)建成功了");
//開(kāi)始寫(xiě)入文件
File file1 = new File(file, "xlj.txt");
Log.d("newtest", "hah: " + file1.toString());
/****
* File file1 = new File(file,"xlj.txt");
* 5.0:/storage/sdcard/Download/testwenjian/xlj.txt
* 7.0: /storage/emulated/0/Download/testwenjian/xlj.txt
* 通過(guò)測(cè)試不難發(fā)現(xiàn),使用具體的文件通過(guò)具體的 流操作就可以完成了, 是文件輸出流,其本身就具有再具體的file路徑下創(chuàng)建文件的功能。
*具體效果見(jiàn)圖二:
*/
String info = "恭喜您,數(shù)據(jù)寫(xiě)入成功了";
try {
FileOutputStream fileOutputStream = new FileOutputStream(file1);
fileOutputStream.write(info.getBytes());
fileOutputStream.close();
mTextView1.setText("創(chuàng)建新的文件成功了");
} catch (FileNotFoundException e) {
e.printStackTrace();
mTextView1.setText("創(chuàng)建新的文件失敗了");
} catch (IOException e) {
e.printStackTrace();
mTextView1.setText("創(chuàng)建新的文件出現(xiàn)了IO異常了");
}
} else {
mTextView1.setText("文件夾未創(chuàng)建成功");
file.delete();
}
}
建立文件夾,如圖一:

最后建立相應(yīng)的文件,如圖二:
在5.0系統(tǒng)下:

在7.0系統(tǒng)下:

另外,保存到外部存儲(chǔ)的公共區(qū)域上如果你想在媒體掃描程序中隱藏您的文件
在您的外部文件目錄中包含名為 `.nomedia` 的空文件(注意文件名中的點(diǎn)前綴)。 這將阻止媒體掃描程序讀取您的媒體文件,
并通過(guò) MediaStore 內(nèi)容提供程序?qū)⑵涮峁┙o其他應(yīng)用。
4、將數(shù)據(jù)保存在外部存儲(chǔ)上的應(yīng)用私有位置上,這樣這些文件只能本應(yīng)用使用,別的應(yīng)用程序無(wú)法訪問(wèn).
簡(jiǎn)單來(lái)講就是五個(gè)方法,五個(gè)方法得到想要操作的文件夾路徑,接下來(lái)就是流的操作,往你想用的文件夾路徑中創(chuàng)建文件或者讀取文件了,所以這里只介紹這五個(gè)方法,對(duì)于流的操作不在寫(xiě)。
當(dāng)用戶(hù)卸載您的應(yīng)用時(shí),此目錄及其內(nèi)容將被刪除。此外,系統(tǒng)媒體掃描程序不回讀取這些目錄中的文件,因此不能從MediaStore內(nèi)容提供程序訪問(wèn)這些文件。同樣,不應(yīng)將這些目錄用于最終屬于用戶(hù)的媒體,例如使用您的應(yīng)用拍攝或編輯照片或者您的應(yīng)用購(gòu)買(mǎi)的音樂(lè)等,這些文件應(yīng)該放在公共的目錄中。
當(dāng)應(yīng)用卸載時(shí)候,這部分內(nèi)容也會(huì)刪除,另外,盡管MediaStore提供的程序不能訪問(wèn)此部分內(nèi)容,但是別的應(yīng)用程序具有READ_XXX權(quán)限的仍可以獲取全部文件時(shí),仍可以得到,所以并不是完全的保密.
(1)getExternalFilesDir(String type)
如果正在處理的文件不適合其他應(yīng)用使用(比如應(yīng)用使用的圖形紋理或者音效),則可以考慮使用外部存儲(chǔ)上的私有存儲(chǔ)目錄。此方法需要傳入type參數(shù)指定子目錄的類(lèi)型。如果不需要特定的目錄,也可以傳遞null獲得應(yīng)用私有目錄的根目錄。也可以指定具體的比如DIRECTORY_MOVIES
從Android 4.4開(kāi)始,讀取或者寫(xiě)入應(yīng)用私有目錄中的文件不在需要READ_EXTERNAL_STORAGE或者WRITE_EXTERNAL_STORAGE權(quán)限,可以通過(guò)添加maxSdkVersion屬性來(lái)聲明,只在較低版本的Android中請(qǐng)求該權(quán)限:
<manifest...>
<users-permission android:name = "android.permission.WRITE_EXTERNAL_STORAGE"
andorid:maxSdkVersion = "18"/>
</manifest>
下面是一些打印的Log:進(jìn)行方法的展示
(1)getExternalFilesDir(null)
5.0:
/storage/sdcard/Android/data/example.xlj.savecundemo/files
7.0:
/storage/emulated/0/Android/data/example.xlj.savecundemo/files
(2)getExternalFilesDir(Environment.DIRECTORY_MOVIES)
5.0:
/storage/sdcard/Android/data/example.xlj.savecundemo/files/Movies
7.0:
/storage/emulated/0/Android/data/example.xlj.savecundemo/files/Movies
(3)getExternalFilesDir("xlj")
/storage/sdcard/Android/data/example.xlj.savecundemo/files/xlj
下面是測(cè)試?yán)樱?/p>
File file = new File(getExternalFilesDir(null), "DemoFile.jpg");
try {
// Very simple code to copy a picture from the application's
// resource into the external file. Note that this code does
// no error checking, and assumes the picture is small (does not
// try to copy it in chunks). Note that if external storage is
// not currently mounted this will silently fail.
InputStream is = getResources().openRawResource(R.raw.my_my_name);
OutputStream os = new FileOutputStream(file);
byte[] data = new byte[is.available()];
is.read(data);
os.write(data);
is.close();
os.close();
} catch (IOException e) {
// Unable to create file, likely because external storage is
// not currently mounted.
Log.w("ExternalStorage", "Error writing " + file, e);
}
在5.0系統(tǒng)下;

在7.0系統(tǒng)下:

(2)getExternalFilesDirs(String type)
與前面getExternalFilesDir方法一樣,不同的是此方法得到的是一個(gè)file[],一般取file[0]使用即可
有時(shí),已分配某個(gè)內(nèi)部存儲(chǔ)器分區(qū)用作外部存儲(chǔ)的設(shè)備可能提供了SD卡槽。在使用運(yùn)行 Android 4.3和更低版本的這類(lèi)設(shè)備時(shí),getExternalFilesDir()方法將僅提供內(nèi)部分區(qū)的訪問(wèn)權(quán)限,而您的應(yīng)用無(wú)法讀取或者寫(xiě)入SD卡。
從Android 4.4開(kāi)始,可以通過(guò)調(diào)用getEx ternalFilesDirs()來(lái)同時(shí)訪問(wèn)這兩個(gè)位置,該方法將會(huì)返回包含各個(gè)位置條目的File數(shù)組。數(shù)組中的第一個(gè)條目被視為外部主存儲(chǔ),除非該位置已滿(mǎn)或者不可用,否則應(yīng)該使用該位置。
如果希望支持Android 4.3和更低版本的同時(shí)訪問(wèn)兩個(gè)可能的位置,請(qǐng)使用支持庫(kù)中的靜態(tài)方法
ContextCompat.getExternalFilesDirs();在Android 4.3或者更低的版本中,此方法也會(huì)返回一個(gè)File數(shù)組,但其中始終包含一個(gè)條目,只能在使用的時(shí)候使用File[0];
盡管MediaStore內(nèi)容提供程序不能訪問(wèn)getExternalFilesDir()和getExternalFilesDirs()所提供的目錄,但其他具有 READ_EXTERNAL_STORAGE權(quán)限的用用仍可訪問(wèn)外部存儲(chǔ)上的所有文件,如上述文件,如果您想要完全限制您的文件訪問(wèn)權(quán)限,則應(yīng)該講您的文件寫(xiě)入到內(nèi)部存儲(chǔ)。
(3)getExternalCacherDir();
5.0
/storage/sdcard/Android/data/example.xlj.savecundemo/cache
7.0
/storage/emulated/0/Android/data/example.xlj.savecundemo/cache
與前面敘述的ContextCompat.getExternalFilesDirs()相似,您也可以通過(guò)調(diào)用ContextCompat.getExternalCacheDirs()來(lái)訪問(wèn)外部存儲(chǔ)上的緩存目錄。
為了節(jié)省文件空間并保持應(yīng)用性能,您應(yīng)該在應(yīng)用的整個(gè)生命周期內(nèi)仔細(xì)管理您的緩存文件并移除其中不再需要的文件。
調(diào)用此方法,得到的文件路徑如圖所示:
5.0系統(tǒng)之下:

7.0系統(tǒng)之下;

(4)getExternalCacherDirs();
此方法與前面提到的getExternalCacherDirs()一樣。其返回值也是Files[];
(5)getExternalMediaDir()
執(zhí)行此方法:
/storage/emulated/0/Android/media/example.xlj.savecundemo
7.0系統(tǒng)之下:

發(fā)現(xiàn)此方法是在Android文件夾下建立了media文件夾,在其中建立了你自己應(yīng)用包名的文件夾,你可以放數(shù)據(jù)。前面提到的四個(gè)方法都是放在了Android/data/應(yīng)用包名/下
數(shù)據(jù)庫(kù)存儲(chǔ)
Android 提供了對(duì)于SQlite數(shù)據(jù)庫(kù)的完全支持,應(yīng)用中的任何類(lèi)(不包括應(yīng)用外部的類(lèi))均可按名稱(chēng)訪問(wèn)您所創(chuàng)建的任何數(shù)據(jù)庫(kù)。
數(shù)據(jù)庫(kù)存儲(chǔ)涉及到兩個(gè)關(guān)鍵類(lèi):
SQLiteDatabase
此類(lèi)SQLiteDatabase公開(kāi)了管理SQLite數(shù)據(jù)庫(kù)的方法。SQLiteDatabase具有創(chuàng)建、刪除、執(zhí)行SQL命令以及執(zhí)行其他常見(jiàn)數(shù)據(jù)庫(kù)管理任務(wù)的方法。
SQLiteOpenHelper
實(shí)際操作是寫(xiě)一個(gè)類(lèi)繼承此類(lèi)
SQLiteOpenHelper是管理數(shù)據(jù)庫(kù)創(chuàng)建和版本管理的助手類(lèi)。
數(shù)據(jù)庫(kù)名稱(chēng)在應(yīng)用中必須是唯一的,而不是跨所有應(yīng)用程序。
比如自己寫(xiě)的一個(gè)例子:
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
//構(gòu)造方法一
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version, DatabaseErrorHandler errorHandler) {
super(context, name, factory, version, errorHandler);
}
//構(gòu)造方法二
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
// super(context, name, factory, version);
//可以通過(guò)外界參數(shù)傳入創(chuàng)建,這里直接賦值了
super(context,"db_openhelper",null,1);
}
//重寫(xiě)的onCreate方法
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL("create table if not exists tb_my(_id integer primary key autoincrement,title text)");
}
//用于更新數(shù)據(jù)庫(kù)版本
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
//參數(shù)一表示以前的版本,oldVersion
//參數(shù)二表示新的版本,newVersion
if (i1 > i){
sqLiteDatabase.execSQL("drop table if exists tb_my");
onCreate(sqLiteDatabase);
}
}
}
在應(yīng)用中使用:
//使用自定義的SQLiteOpenHelper
MySQLiteOpenHelper mySQLiteOpenHelper = new MySQLiteOpenHelper(this,"",null,1);
//執(zhí)行完上局話得到。。什么反應(yīng)也沒(méi)有
SQLiteDatabase sqLiteDatabase = mySQLiteOpenHelper.getReadableDatabase();
//通過(guò)幫助類(lèi)得到管理數(shù)據(jù)庫(kù)的方法。便會(huì)得到在內(nèi)部存儲(chǔ)中建立相應(yīng)的數(shù)據(jù)庫(kù)
sqLiteDatabase.insert("tb_my","title",null);
結(jié)果:

寫(xiě)給自己的備注:
關(guān)于數(shù)據(jù)庫(kù)這邊簡(jiǎn)單記錄一下,上面涉及到的兩個(gè)鏈接都是Google官方提供的資料,計(jì)劃在整理新的文檔,因?yàn)槠渖婕暗倪€是比較多的。整理完成后,將Google提供的鏈接替換成自己文章的鏈接。
網(wǎng)絡(luò)存儲(chǔ)
所謂的網(wǎng)絡(luò)存儲(chǔ)簡(jiǎn)單來(lái)講,就是將數(shù)據(jù)資料放在網(wǎng)絡(luò)服務(wù)器上。
由于市面上的網(wǎng)絡(luò)框架比較多,就不做詳細(xì)介紹了。下面提供兩個(gè)Google推薦的兩個(gè)參考類(lèi)、