Android的多種數(shù)據(jù)存儲(chǔ)方法
掃描二維碼
隨時(shí)隨地手機(jī)看文章
Android為你提供了若干選項(xiàng)用于存儲(chǔ)應(yīng)用程序數(shù)據(jù)。選擇何種方案時(shí)情況而定。比如,數(shù)據(jù)僅為你的應(yīng)用所使用,或是可是為其他應(yīng)用(以及用戶)所共享。又比如,你的數(shù)據(jù)需要多少空間。
數(shù)據(jù)存儲(chǔ)有以下幾個(gè)選擇:
Data_Storage#.E4.BD.BF.E7.94.A8.E5.85.B1.E4.BA.AB.E7.9A.84.E9.85.8D.E7.BD.AE_-_Using_Shared_Preferences|Shared Preferences|公共配置-Shared Preferences
通過鍵值對(duì)的方式存儲(chǔ)私有的原始數(shù)據(jù)。
Data_Storage#.E4.BD.BF.E7.94.A8.E5.86.85.E9.83.A8.E5.AD.98.E5.82.A8_-_Using_the_Internal_Storage|Internal Storage|內(nèi)部存儲(chǔ)-Internal Storage
在存儲(chǔ)器上存儲(chǔ)私有的數(shù)據(jù)。
Data_Storage#.E4.BD.BF.E7.94.A8.E5.86.85.E9.83.A8.E5.AD.98.E5.82.A8_-_Using_the_Internal_Storage|External Storage | 外部存儲(chǔ) - External Storage
在外部存儲(chǔ)器上存儲(chǔ)公開的數(shù)據(jù)。
Data_Storage#.E4.BD.BF.E7.94.A8.E6.95.B0.E6.8D.AE.E5.BA.93_-_Using_Databases|SQLite Database | SQLite數(shù)據(jù)庫 - SQLite Database
在私有的數(shù)據(jù)庫中存儲(chǔ)結(jié)構(gòu)化的數(shù)據(jù)。
Data_Storage#.E4.BD.BF.E7.94.A8.E7.BD.91.E7.BB.9C.E8.BF.9E.E6.8E.A5_-_Using_a_Network_Connection|Network Connection | 網(wǎng)絡(luò)連接 - Network Connection
使用你的網(wǎng)絡(luò)服務(wù)器存儲(chǔ)數(shù)據(jù)。
Android提供了暴露私有數(shù)據(jù)給其他應(yīng)用的方法——使用一個(gè)內(nèi)容提供器(content provider)。內(nèi)容提供器是一個(gè)可選的組件,為你的應(yīng)用程序數(shù)據(jù)提供讀/寫權(quán)限,并受制于你給定的限制。關(guān)于使用內(nèi)容提供器的更多細(xì)節(jié),請(qǐng)查看Content Providers的文檔。
使用共享的配置 - Using Shared Preferences
SharedPreferences類提供了一個(gè)通用的框架,用于保存和檢索以持久化的鍵值對(duì)形式存儲(chǔ)的原始數(shù)據(jù)類型。你可以使用SharedPreferences保存任意類型的原始數(shù)據(jù):布爾(boolean),浮點(diǎn),(float),整型(int),長整型(long)和字符串(string)。這些數(shù)據(jù)將會(huì)存放在用戶會(huì)話中(即使你的應(yīng)用程序已經(jīng)退出)。
* 用戶配置*
共享的配置并非一定要保存"用戶配置",例如用戶選擇和哪個(gè)鈴聲。如果你有興趣為你的應(yīng)用創(chuàng)建用戶配置,請(qǐng)參考PreferenceActivity。它提供了一個(gè)Activity的框架,可以用來創(chuàng)建持久化的用戶配置(使用共享的配置)。
在應(yīng)用程序中取得SharedPreferences對(duì)象,使用以下兩種方法之一:
* int) getSharedPreferences() getPreferences()](http://developer.android.com/reference/android/content/Context.html#getSharedPreferencesjava.lang.String,)( - 當(dāng)你僅需要一個(gè)配置文件。由于這是你的Activity的唯一一個(gè)配置文件,所以不必提供名稱。
向SharedPreferences寫入值的步驟:
1、調(diào)用edit(),取得一個(gè)SharedPreferences.Editor。
2、使用形如boolean) putBoolean() putString()](http://developer.android.com/reference/android/content/SharedPreferences.Editor.html#putStringjava.lang.String,)這樣的方法添加值。(
3、使用commit()提交新值。
從SharedPreferences讀取值,使用它的方法,例如boolean) getBoolean() getString()](http://developer.android.com/reference/android/content/SharedPreferences.html#getStringjava.lang.String,)即可。(
這是一個(gè)例子,在一個(gè)計(jì)算器中使用無聲的按鍵保存一個(gè)配置:
class extends { static String PREFS_NAME ; protected (){ .onCreate); . // Restore preferences "color:#660">(PREFS_NAME0boolean silent settings(, ); setSilent); @Override void onStopsuper(); // All objects are from android.context.Context "color:#660">(PREFS_NAME0SharedPreferencesEditor editor settings(); editor(, mSilentMode// Commit the edits! editor(); }
使用內(nèi)部存儲(chǔ) - Using the Internal Storage
你可以直接將文件保存在設(shè)備上的內(nèi)部存儲(chǔ)中。缺省情況下,存放于內(nèi)部存儲(chǔ)的文件為你的應(yīng)用程序所私有,其他應(yīng)用程序不能夠訪問它們(其他用戶亦然)。當(dāng)用戶卸載你的應(yīng)用,這些文件也被刪除。
在內(nèi)部存儲(chǔ)中創(chuàng)建并寫入一個(gè)私有文件:
1、調(diào)用openFileOutput(),傳入文件名和操作模式。方法返回一個(gè)FileOutputStream對(duì)象。
2、使用write()寫文件。
3、使用close()關(guān)閉文件流。
例如:
"color:#080">"hello_file"String "color:#080">"hello world!"FileOutputStream fos openFileOutput, .MODE_PRIVATE.writestring());fos();
MODE_PRIVATE創(chuàng)建文件(或以同名文件替換),并為你的應(yīng)用所私有。其他可用的模式有:MODE_APPEND, MODE_WORLD_READABLE, 和MODE_WORLD_WRITEABLE。
從內(nèi)部存儲(chǔ)中讀一個(gè)文件:
1、調(diào)用openFileInput(),并傳遞需要讀取的文件的名稱。這個(gè)方法返回一個(gè)FileInputStream。
2、使用read()從文件中讀取數(shù)據(jù)。
3、使用close()關(guān)閉文件流。
提示:如果你想在編譯時(shí)往你的應(yīng)用中存入一個(gè)靜態(tài)文件,就得把文件保存到項(xiàng)目的res/raw目錄下。你可以調(diào)用openRawResource()并傳遞資源的ID(R.raw.)來打開它。這個(gè)方法返回一個(gè)InputStream,你可以使用它讀取文件,但不能夠?qū)懭脒@個(gè)原始文件。
保存緩存文件
如果你想要緩存一些數(shù)據(jù),而不是保存它們,你應(yīng)該調(diào)用getCacheDir()打開一個(gè)File對(duì)象,它表示你的應(yīng)用應(yīng)當(dāng)保存臨時(shí)緩存文件的內(nèi)部目錄。
其他有用的方法
getFilesDir() 取得內(nèi)部文件在文件系統(tǒng)中保存位置的絕對(duì)路徑。
getDir() 創(chuàng)建(或者打開已存在的)內(nèi)部存儲(chǔ)空間所在的目錄。
deleteFile() 刪除內(nèi)部存儲(chǔ)的一個(gè)文件。
fileList() 返回當(dāng)前由你的應(yīng)用保存的文件的列表。
使用外部存儲(chǔ) - Using the External Storage
所有兼容Android的設(shè)備都支持一個(gè)可共享的“外部存儲(chǔ)(external storage)”,可用來保存文件。這可以使一個(gè)可移動(dòng)的存儲(chǔ)設(shè)備(比如SD卡)或者一個(gè)內(nèi)部的(不可移動(dòng)的)存儲(chǔ)。保存在外部存儲(chǔ)的文件是可讀的。并且當(dāng)用于傳輸數(shù)據(jù)的USB大容量存儲(chǔ)選項(xiàng)啟用時(shí),用戶能夠在計(jì)算機(jī)上修改它們。
注意:* 如果用戶掛載外部存儲(chǔ)到計(jì)算機(jī)上,或者移除媒體,外部文件將會(huì)消失不見。并且對(duì)于這些保存在外部存儲(chǔ)的文件,沒有強(qiáng)制的安全措施。所有的應(yīng)用都可以讀/寫這些文件。用戶也能夠刪除它們。
檢測(cè)媒體可用性
在你對(duì)外部存儲(chǔ)做任何事情之前,你總是應(yīng)當(dāng)調(diào)用getExternalStorageState()以檢測(cè)媒體是否可用。媒體可能被計(jì)算機(jī)掛載,可能丟失,可能只讀,或者處于某些其他狀態(tài)。比如,這是示例代碼:
"color:#008">falseboolean mExternalStorageWriteable ;"color:#606">Environment();(.MEDIA_MOUNTED(state{ "color:#660">"color:#008">true} if Environment.equals)) // We can only read the media mExternalStorageAvailable ; mExternalStorageWriteable ;else // Something else is wrong. It may be one of many other states, but all we need "color:#660">"color:#008">false}
這個(gè)例子檢測(cè)了外部存儲(chǔ)是否可讀或可寫。getExternalStorageState()方法返回你想要檢測(cè)的其他狀態(tài)。比如,媒體是否被共享(已連接到一臺(tái)計(jì)算機(jī)),是否完全丟失,是否被移除等等。當(dāng)你的應(yīng)用需要訪問媒體時(shí),你可以依據(jù)這些以更詳細(xì)的信息通知用戶。
訪問位于外部存儲(chǔ)的文件
如果你正在使用API Level 8或者更高版本,使用getExternalFilesDir()打開一個(gè)文件對(duì)象,它表示你的應(yīng)用應(yīng)當(dāng)保存文件所在的外部存儲(chǔ)目錄。這個(gè)方法需要一個(gè)類型參數(shù),指定你需要的子目錄類型,比如DIRECTORY_MUSIC或者DIRECTORY_RINGTONES(傳遞null表示你的應(yīng)用程序的目錄所在的根目錄)。如有必要,這個(gè)方法將會(huì)創(chuàng)建一個(gè)目錄。通過指定目錄的類型,你確信Android的媒體掃描器會(huì)將系統(tǒng)中的文件正確分類(例如,鈴聲將被歸類為鈴聲而不是音樂)。如果用戶卸載了你的應(yīng)用,這個(gè)目錄以及它的內(nèi)容將會(huì)被刪除。
如果你正在使用API Level 7或者更低版本,使用getExternalStorageDirectory()打開一個(gè)文件對(duì)象,它表示外部存儲(chǔ)的根目錄。接下來,你應(yīng)當(dāng)寫入你的數(shù)據(jù)在一下目錄:
/Android/data//files/
"com.example.android.app"。如果用戶的設(shè)備正在運(yùn)行API Level 8或者更高版本,且用戶卸載了你的應(yīng)用,這個(gè)目錄和它的內(nèi)容將會(huì)被刪除。
保存應(yīng)當(dāng)共享的文件
在媒體掃描器下隱藏你的文件
在你的外部文件目錄中放置包括一個(gè)空的文件,命名為.nomedia(注意文件名前綴的點(diǎn))。這會(huì)阻止Android的媒體掃描器讀取你的媒體文件,并并在類似Gallery或者M(jìn)usic這樣的應(yīng)用中包括它們。
如果你想要保存與你的應(yīng)用沒有關(guān)聯(lián)的文件,并且這些文件不應(yīng)在應(yīng)用卸載時(shí)被刪除,把他們保存在外部存儲(chǔ)的一個(gè)公共目錄上即可。這些目錄位于外部存儲(chǔ)的根目錄下,比如Music/, Pictures/, Ringtones/,以及其它目錄。
在API Level 8或者更高版本,調(diào)用getExternalStoragePublicDirectory(),傳遞你需要的公共目錄的類型,比如DIRECTORY_MUSIC, DIRECTORY_PICTURES, DIRECTORY_RINGTONES或者其它。如有必要,這個(gè)方法會(huì)創(chuàng)建新目錄。
如果你正在使用API Level 7或者更低版本,調(diào)用getExternalStorageDirectory()打開一個(gè)File,它表示外部存儲(chǔ)的根目錄。接著保存你的共享文件在以下文件夾之一:
Music/ - 媒體掃描器把所有在此發(fā)現(xiàn)的媒體歸類為用戶的音樂。
Podcasts/ - 媒體掃描器把所有在此發(fā)現(xiàn)的媒體歸類為播客。
Ringtones/ - 媒體掃描器把所有在此發(fā)現(xiàn)的媒體歸類為鈴聲。
Alarms/ - 媒體掃描器把所有在此發(fā)現(xiàn)的媒體歸類為鬧鈴。
Notifications/ - 媒體掃描器把所有在此發(fā)現(xiàn)的媒體歸類為提示音。
Pictures/ - 所有照片(相機(jī)拍攝的除外)。
Movies/ - 所有影片(攝像機(jī)拍攝的除外)。
Download/ - 各類下載。
保存緩存文件
如果你正在使用API Level 8或者更高版本,調(diào)用getExternalCacheDir()打開一個(gè)File,它表示你的應(yīng)用應(yīng)當(dāng)保存文件所在的外部存儲(chǔ)目錄。如果用戶卸載了你的應(yīng)用,這些文件會(huì)被自動(dòng)刪除。然而,在你的應(yīng)用的生命周期中,你應(yīng)當(dāng)管理這些緩存文件以及刪除其中過期的部分以保證文件空間。
如果你正在使用API Level 7或者更低版本,使用getExternalStorageDirectory()打開一個(gè)File,它表示外部存儲(chǔ)的根目錄。接下來,你應(yīng)當(dāng)寫入你的數(shù)據(jù)在一下目錄:
/Android/data//files/
"com.example.android.app"。
使用數(shù)據(jù)庫 - Using Databases
Android提供了對(duì)SQLite數(shù)據(jù)庫的完整支持。你創(chuàng)建的任何數(shù)據(jù)庫都能被應(yīng)用程序中的任意類通過數(shù)據(jù)庫名訪問。但是不能夠在應(yīng)用程序以外訪問。
推薦的創(chuàng)建新的SQLite數(shù)據(jù)庫的方法是,在你執(zhí)行SQLite命令在數(shù)據(jù)庫中創(chuàng)建表的時(shí)候,創(chuàng)建一個(gè)SQLiteOpenHelper的子類,并重寫onCreate()方法。例如:
class extends { static int DATABASE_VERSION ; static String DICTIONARY_TABLE_NAME ; static String DICTIONARY_TABLE_CREATE + DICTIONARY_TABLE_NAME " (" + + KEY_DEFINITION " TEXT);"DictionaryOpenHelperContext context{ (context, , DATABASE_VERSION} public () .execSQL); }
接著,你可以使用構(gòu)造方法取得你實(shí)現(xiàn)的SQLiteOpenHelper的一個(gè)實(shí)例。分別使用getWritableDatabase()和getReadableDatabase()讀寫數(shù)據(jù)庫。兩者都會(huì)返回一個(gè)SQLiteDatabase對(duì)象,代表那個(gè)數(shù)據(jù)庫,并提供操作SQLite的方法。
Android沒有在標(biāo)準(zhǔn)SQLite概念之外加以任何限制。我們建議包含一個(gè)自增值的主鍵字段,能夠作為一個(gè)唯一的ID,以便快速定位一條記錄。這對(duì)私有數(shù)據(jù)來說不是必須的。但如果你實(shí)現(xiàn)了一個(gè)content provider,就必須包含一個(gè)唯一的ID,它使用BaseColumns._ID常量。
你可以使用SQLiteDatabase.query()方法執(zhí)行SQLite查詢,這個(gè)方法接受各種查詢參數(shù),例如待查詢的表、投影、選擇、列、組,或者其他。對(duì)于復(fù)雜查詢,比如一些需要用到列的別名的,你應(yīng)當(dāng)使用SQLiteQueryBuilder,它能提供一些合適的方法以創(chuàng)建查詢。
每一個(gè)SQLite查詢都會(huì)返回一個(gè)Cursor對(duì)象,指向查詢得到的所有行。Cursor對(duì)象總是你用來取得數(shù)據(jù)庫查詢或者讀取行或列的結(jié)果的途徑。
關(guān)于示例應(yīng)用中演示如何在Android中使用SQLite數(shù)據(jù)庫,見Node Pad和Searchable Dictionary這兩個(gè)應(yīng)用。
數(shù)據(jù)庫調(diào)試
Android SDK包含了一個(gè)sqlite3的數(shù)據(jù)庫工具,允許你瀏覽表內(nèi)容,運(yùn)行SQL命令,以及執(zhí)行其他SQLite數(shù)據(jù)庫中有用的功能。想要了解如何運(yùn)行這個(gè)工具,請(qǐng)查看Examining sqlite3 databases from a remote shell這個(gè)例子。
使用網(wǎng)絡(luò)連接 - Using a Network Connection
你可以使用網(wǎng)絡(luò)連接(當(dāng)可用時(shí))通過基于web的服務(wù)存儲(chǔ)或取得數(shù)據(jù)。需要執(zhí)行網(wǎng)絡(luò)操作時(shí),使用以下包中的類:
java.net.*
android.net.*