谷歌官方文檔:Android API之數(shù)據(jù)儲存
本文將簡述Android API的數(shù)據(jù)儲存 (Data Storage)工作機制,希望本文能對正在做Android開發(fā)的朋友有所幫助。
數(shù)據(jù)儲存 (Data Storage)
Android為你提供了多個可選的方式來保存持久的應用數(shù)據(jù)。你可以基于特定的需求來選擇解決方案,例如數(shù)據(jù)是否應該是你的應用私有的還是對其他應用(和用戶)公開的以及你的數(shù)據(jù)需要多大的空間來儲存。
你可選的數(shù)據(jù)儲存方式如下:
◆Shared Preferences 共享偏好
以"鍵-值對"的形式儲存私有的基礎數(shù)據(jù)。
◆Internal Storage 內(nèi)部存儲器
儲存私有數(shù)據(jù)到設備內(nèi)存。
◆External Storage 外部存儲器
儲存公有數(shù)據(jù)到共享的外部儲存器。
◆SQLite Databases SQLite數(shù)據(jù)庫
用一個私有的數(shù)據(jù)庫儲存結構化數(shù)據(jù)。
◆Network Connection 網(wǎng)絡連接
通過你自己的服務器儲存數(shù)據(jù)到網(wǎng)絡。
Android為你提供了一個途徑來暴露你私有數(shù)據(jù)給其他的應用程序 —— 通過一個content provider 。一個content provider是一個可選組件,暴露你的應用程序數(shù)據(jù)的read/write接口,遵循任何可能引入的約定。更多關于content provider使用的信息,請查閱Content Providers 文檔.
使用Shared Preferences (Using Shared Preferences)
SharedPreferences 類提供了一個通用的框架來允許你以"鍵-值對"的形式來儲存和獲取持久的基礎數(shù)據(jù)。你可以使用SharedPreferences 來保存任何基礎數(shù)據(jù):boolean, float, int, long和String。這些數(shù)據(jù)將存留橫跨用戶對話(即使你的應用程序被殺死了)。
User Preferences Shared preferences are not strictly for saving "user preferences," such as what ringtone a user has chosen. If you're interested in creating user preferences for your application, see PreferenceActivity , which provides an Activity framework for you to create user preferences, which will be automatically persisted (using shared preferences). |
要給你的應用獲取一個SharedPreference 對象,使用以下的兩個函數(shù)之一:
getSharedPreferences() - 如果你需要多個通過名字來識別的偏好文件請使用該函數(shù),名字通過***個參數(shù)來設定。
getPreferences() - 如果你的Activity僅需要一個偏好文件請使用該函數(shù)。因為這會是你的Activity獨有的偏好文件,你不用提供一個文件名。
寫入數(shù)值:
1.調(diào)用edit() 函數(shù)來獲得一個SharedPreferences.Editor 對象。
2.通過putBoolean() 、putString() 等函數(shù)來添加數(shù)值。
3.通過commit() 函數(shù)來提交和確認操作。
要讀取數(shù)值,使用SharedPreferences 中的getBoolean() 、getString() 等函數(shù)。
這里是一個例子,為一個計算器的按鍵靜音模式保存了一個偏好:
Java代碼
- public class Calc extends Activity {
- public static final String PREFS_NAME = "MyPrefsFile";
- @Override
- protected void onCreate(Bundle state) {
- super.onCreate(state);
- . . .
- // Restore preferences
- SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
- boolean silent = settings.getBoolean("silentMode", false);
- setSilent(silent);
- }
- @Override
- protected void onStop() {
- super.onStop();
- // We need an Editor object to make preference changes.
- // All objects are from android.context.Context
- SharedPreferences settings = getSharedPreferences(PREFS_NAME, 0);
- SharedPreferences.Editor editor = settings.edit();
- editor.putBoolean("silentMode", mSilentMode);
- // Commit the edits!
- editor.commit();
- }
- }
使用內(nèi)部存儲器 (Using the Internal Storage)
你可以直接將文件保存到設備的內(nèi)部存儲器上。默認的,保存到內(nèi)部存儲器上的文件是對你的應用私有的并且其他應用無法訪問它們(用戶也不行)。當用戶卸載你的應用,這些文件會被移除。
要創(chuàng)建和寫入一個私有文件到內(nèi)部存儲器:
1.通過文件名和處理模式調(diào)用openFileOutput() 函數(shù)。返回的是一個FileOutputStream 對象。
2.使用write() 函數(shù)來寫入文件。
3.使用close() 函數(shù)來關閉流。
For example:
Java代碼
- String FILENAME = "hello_file";
- String string = "hello world!";
- FileOutputStream fos = openFileOutput(FILENAME, Context.MODE_PRIVATE);
- fos.write(string.getBytes());
- fos.close();
MODE_PRIVATE 會創(chuàng)建文件并使它對你的應用私有。其他可用的模式有:MODE_APPEND 、MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE。
要從內(nèi)部存儲器中讀取一個文件:
1.調(diào)用openFileInput() 函數(shù)并傳遞一個文件名來讀取。返回的是一個FileInputStream 對象。
2.使用read() 函數(shù)讀取文件中的字節(jié)。
3.然后使用close() 函數(shù)關閉流。
提示 :如果你希望在編譯的時候保存一個靜態(tài)的文件到你的應用中,將文件保存到你項目的res/raw/ 目錄下。你使用openRawResource() 函數(shù)可以打開它,傳遞一個R.raw.<filename> 資源ID。該函數(shù)返回一個你可以用來讀取文件的InputStream 對象(但你無法改寫原始文件)。
保存緩存文件 (Saving cache files)
如果你想緩存一些數(shù)據(jù),而不是***儲存,你應該使用getCacheDir() 來打開一個代表內(nèi)部存儲器中儲存臨時緩存文件的目錄的File 對象。
當設備的內(nèi)部儲存空間較低時,Android可能會刪除這些緩存文件來取回空間。無論如何,你不應該依靠系統(tǒng)來為你清空這些文件。你應該始終自己來維護緩存文件并維持在一個合理的空間消耗,比如1MB。當用戶卸載你的應用,這些文件會被移除。
其他有用的函數(shù) (Other useful methods)
◆getFilesDir()
獲取你的內(nèi)部文件所儲存的系統(tǒng)目錄的絕對路徑。
◆getDir()
在你的內(nèi)部存儲器空間中創(chuàng)建(或打開一個存在的)目錄。
◆deleteFile()
刪除一個保存在內(nèi)部存儲器上的文件。
◆fileList()
返回一個你的應用當前保存了的文件的數(shù)組。#p#
使用外部存儲器 (Using the External Storage)
每個兼容Android的設備都支持一個共享的"外部存儲器",你可以用它來儲存文件。這可以是可被移除的存儲媒介(例如一個SD卡)或是一個內(nèi)部存儲器 (不可被移除)。儲存在外部存儲器中的文件都是world-readable屬性并且可以被用戶修改(當他們允許USB大儲存器在電腦上轉(zhuǎn)移文件時)。
警告 :里面的這些外部文件是會消失不可見的——如果用戶把外部存儲器掛在到一臺電腦上或移除該媒介(SD卡),同時你儲存在外部儲存器上的文件沒有強制的安全保證。所有應用程式都可以讀寫這些文件并且用戶也可以刪除它們。 |
檢測媒介是否可用 (Checking media availability)
在你對外部存儲器進行任何操作之前,你應該始終調(diào)用getExternalStorageState() 函數(shù)來檢測媒介是否處于可用狀態(tài)。媒介可能被掛載到一臺電腦上、遺失、只讀或處于其他狀態(tài)。例如,你可以像這里這樣來檢測其是否可用:
Java代碼
- boolean mExternalStorageAvailable = false;
- boolean mExternalStorageWriteable = false;
- String state = Environment.getExternalStorageState();
- if (Environment.MEDIA_MOUNTED.equals(state)) {
- // We can read and write the media
- mExternalStorageAvailable = mExternalStorageWriteable = true;
- } else
- if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
- {
- // We can only read the media
- mExternalStorageAvailable = true;
- mExternalStorageWriteable = false;
- } else {
- // Something else is wrong. It may be one of many other states, but all we need
- // to know is we can neither read nor write
- mExternalStorageAvailable = mExternalStorageWriteable = false;
- }
這個例子檢測外部存儲器是否可用于讀和寫。你可能希望檢測getExternalStorageState() 函數(shù)返回的其他狀態(tài),例如媒介是否被共享了(連接到了電腦)、是否完全遺失了、被意外移除了等等。當你的應用需要訪問媒介的時候,你可以使用這些(攜帶更多的信息)來提示用戶。
訪問外部存儲器上的文件 (Accessing files on external storage)
如果你使用的是API Level 8或更高版本,使用getExternalFilesDir() 函數(shù)來打開一個代表外部存儲器目錄(你最終儲存文件的地方)的File 對象。該函數(shù)使用一個type 參數(shù)來指定你希望的子目錄的類型,例如 DIRECTORY_MUSIC 和 DIRECTORY_RINGTONES (傳null 值,會返回你應用文件目錄的根目錄)。該函數(shù)會在需要時創(chuàng)建合適的目錄。
如果你使用的是API Level 7或更低的版本,使用getExternalStorageDirectory() 函數(shù)來打開一個代表外部存儲器根目錄的File 對象。然后,你應該將你的數(shù)據(jù)寫入到以下的目錄:
/Android/data/<package_name> /files/<package_name> 是你的Java風格的包名,比如"com.example.android.app "。如果用戶的設備正在運行的是API Level 8或更高的版本,那么在你的應用被卸載后,該目錄及其中的所有內(nèi)容都將被刪除掉。
從Media Scanner中隱藏你的文件 包含一個命名為 .nomedia 的空文件到你的外部文件目錄(注意文件名中的點前綴)。這樣會防止Android的media scanner通過讀取你的媒介文件并包含他們到應用中,想畫廊或音樂。 |
保存可被共享的文件 (Saving files that should be shared)
如果你希望保存的文件并不特定于你的應用并且不會在應用卸載時被刪除,請將他們保存到外部存儲器上的一個公有目錄。這些目錄放置在外部存儲器的根目錄下,比如 Music/ , Pictures/ , Ringtones/ 及其他。
在API Level 8或更高版本中,使用 getExternalStoragePublicDirectory() 函數(shù),傳給它一個你希望的公有目錄類型,比如 DIRECTORY_MUSIC , DIRECTORY_PICTURES, DIRECTORY_RINGTONES或其他。該函數(shù)將在必要的時候創(chuàng)建合適的目錄。
如果你使用的是API Level 7或更低的版本,使用getExternalStorageDirectory() 函數(shù)來打開一個代表外部存儲器根目錄的File 對象。然后,儲存你的共享文件到以下目錄中的一個里面:
- Music/ - Media scanner classifies all media found here as user music.
- Podcasts/ - Media scanner classifies all media found here as a podcast.
- Ringtones/ - Media scanner classifies all media found here as a ringtone.
- Alarms/ - Media scanner classifies all media found here as an alarm sound.
- Notifications/ - Media scanner classifies all media found here as a notification sound.
- Pictures/ - All photos (excluding those taken with the camera).
- Movies/ - All movies (excluding those taken with the camcorder).
- Download/ - Miscellaneous downloads.
保存緩存文件 (Saving cache files)
如果你使用的是API Level 8或更高的版本,使用getExternalCacheDir() 函數(shù)來打開一個代表外部存儲器中你將儲存緩存文件的目錄的File 對象。如果用戶卸載你的應用,這些文件將會被自動刪除。無論如何,在你應用的生命中,你應該管理這些緩存文件并在不再需要的時候移除它們以便保存文件空間。
如果你使用的是API Level 7或更低的版本,使用getExternalStorageDirectory() 函數(shù)來打開一個代表外部存儲器根目錄的File 對象,然后將你的緩存數(shù)據(jù)寫入到下面的目錄:/Android/data/<package_name> /cache/<package_name> 是你的Java風格的包名,比如"com.example.android.app "。
使用數(shù)據(jù)庫 (Using Databases)
Android提供了對SQLite 數(shù)據(jù)庫的完整支持。任何你所創(chuàng)建的數(shù)據(jù)庫在應用中的任何一個類中都可以通過其文件名來訪問到,但無法在應用外部訪問。
創(chuàng)建一個新的SQLite數(shù)據(jù)庫,推薦的方式是創(chuàng)建一個SQLiteOpenHelper 的子類并重寫其onCreate() 函數(shù),在該函數(shù)中執(zhí)行SQLite命令來在數(shù)據(jù)庫中創(chuàng)建表。例如:
Java代碼
- public class DictionaryOpenHelper extends SQLiteOpenHelper {
- private static final int DATABASE_VERSION = 2;
- private static final String DICTIONARY_TABLE_NAME = "dictionary";
- private static final String DICTIONARY_TABLE_CREATE =
- "CREATE TABLE " + DICTIONARY_TABLE_NAME + " (" +
- KEY_WORD + " TEXT, " +
- KEY_DEFINITION + " TEXT);";
- DictionaryOpenHelper(Context context) {
- super(context, DATABASE_NAME, null, DATABASE_VERSION);
- }
- @Override
- public void onCreate(SQLiteDatabase db) {
- db.execSQL(DICTIONARY_TABLE_CREATE);
- }
- }
然后你可以使用你已定義的構造函數(shù)來獲得一個你實現(xiàn)的SQLiteOpenHelper 實例。調(diào)用 getWritableDatabase() 函數(shù)和getReadableDatabase() 函數(shù)分別來寫進或讀出數(shù)據(jù),兩個函數(shù)都會返回一個表示數(shù)據(jù)庫的SQLiteDatabase 對象,并為SQLite的操作提供了函數(shù)。
Android沒有在標準的SQLite概念上添加任何限制。我們推薦包含一個自動增量數(shù)值鍵字段來被用于作為一個***的ID,以便快速找到一個記錄。這不需要是一個私有數(shù)據(jù),但如果你實現(xiàn)了一個 content provider ,你就必須使用BaseColumns._ID 常量來包含一個***的ID。 |
你可以使用SQLiteDatabase 的query() 函數(shù)來執(zhí)行SQLite的查詢,query() 函數(shù)支持各種查詢參數(shù),例如查詢表時就有projection, selection, columns, grouping等參數(shù)可配置。對于復雜的查詢,例如那些需要列別名的,你應該使用SQLiteQueryBuilder ,它提供了多個便捷的函數(shù)可用于構建查詢。
每個SQLite查詢都會返回一個Cursor 對象,它指向查詢所找到的所有的行。Cursor 永遠是你操縱數(shù)據(jù)庫查詢結果及讀取行和列的途徑。
作為Android中展示了如何使用SQLite數(shù)據(jù)庫的例子,請查看Note Pad 和Searchable Dictionary 應用。
數(shù)據(jù)庫調(diào)試 (Database debugging)
Android SDK包含了一個數(shù)據(jù)庫工具來允許你瀏覽表格的內(nèi)容,在SQLite數(shù)據(jù)庫上運行SQL命令,并執(zhí)行其他有用的方法。查閱Examining sqlite3 databases from a remote shell 學習如何運行該工具。
使用網(wǎng)絡連接 (Using a Network Connection)
你可以在你自己的基于網(wǎng)絡的服務器上使用網(wǎng)絡(當它可用的時候)來儲存和接收數(shù)據(jù)。要執(zhí)行網(wǎng)絡操作,使用下面的包中的類:java.net.* android.net.*
原文請查閱:http://developer.android.com.nyud.net/guide/topics/data/data-storage.html
【編輯推薦】