Android中數(shù)據(jù)存儲(chǔ)與文件存儲(chǔ)

前言

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ǔ)

微信截圖_20190305114614.png

一、使用共享首選項(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)用包名下:


初始未進(jìn)行操作時(shí)候應(yīng)用的樣子.png

當(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();
建立相應(yīng)的SharedPreferences.png

(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

使用第二種方法.png

在手機(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ǔ)如下圖:


初始.png

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é)果如圖:


結(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é)果:


結(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異常了");
                }
            }
GIF.gif

通過(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é)果如圖:


結(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異常了");
                }
演示cache.png

忽略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();
        }
結(jié)果.png

如圖中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)備文件:


WTISQN`{LBKB234VF2$812T.png

演示讀取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異常了");
                }
結(jié)果

演示如何讀取一個(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ū)域:
前言圖.png

一般來(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)下:


7.0測(cè)試一外部存貯.png

另外,保存到外部存儲(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)下;


5.0系統(tǒng)之下.png

在7.0系統(tǒng)下:


7.0測(cè)試隱私文件存儲(chǔ).png
(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)之下:


測(cè)試存儲(chǔ)緩存隱私文件.png

7.0系統(tǒng)之下;


7.0測(cè)試緩存存儲(chǔ).png
(4)getExternalCacherDirs();

此方法與前面提到的getExternalCacherDirs()一樣。其返回值也是Files[];

(5)getExternalMediaDir()

執(zhí)行此方法:

/storage/emulated/0/Android/media/example.xlj.savecundemo

7.0系統(tǒng)之下:


結(jié)果

發(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é)果:


O5{@J1246`E4CL(S5%7NRWC.png

寫(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)、

java.net.*
android.net.*

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,204評(píng)論 25 708
  • ¥開(kāi)啟¥ 【iAPP實(shí)現(xiàn)進(jìn)入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開(kāi)一個(gè)線程,因...
    小菜c閱讀 7,362評(píng)論 0 17
  • 以前看到更多的論調(diào)說(shuō)的都是要活在當(dāng)下,享受當(dāng)下的幸福與快樂(lè)。 可又有話說(shuō):人無(wú)遠(yuǎn)慮必有近憂。 其實(shí)兩句話并不矛盾。...
    邵公子GZS閱讀 185評(píng)論 0 0
  • 作為“民國(guó)四大才女”之一的張愛(ài)玲,其作品以獨(dú)特的風(fēng)格聞名于世,其小說(shuō)大多表現(xiàn)男女之間的情感,細(xì)膩而又冷峻,讀罷只覺(jué)...
    不思齋主人閱讀 473評(píng)論 0 0
  • 春鋤 一鋤寒冬去, 鳥(niǎo)語(yǔ)花香惹人醉。 不問(wèn)曾經(jīng)苦, 只待馨蘭聞信回。 二鋤黃土語(yǔ), 春雨時(shí)節(jié)攜手隨。 昨夜翩小樓,...
    8d660c73f57e閱讀 620評(píng)論 0 0

友情鏈接更多精彩內(nèi)容