將數據保存到數據庫對於重複或結構化數據而言是理想之選。 本課程假定您基本熟悉 SQL 數據庫並且可幫助您開始在 Android 中使用 SQLite 數據庫。 您在 Android 中使用數據庫所需的 API 在 android.database.sqlite 包中提供。
定義schema和contract
SQL 數據庫的主要原則之一是schema:數據庫如何組織的正式聲明。 schema體現於您用於創建數據庫的 SQL 語句。您會發現它有助於創建伴隨類,即contract類,其以一種系統性、自記錄的方式明確指定您的schema佈局。
contract類是用於定義 URI、table和列名稱的常數的容器。 contract類允許您跨同一軟件包中的所有其他類使用相同的常數。 您可以在一個位置更改列名稱並使其在您整個代碼中傳播。
組織contract類的一種良好方法是將對於您的整個數據庫而言是全局性的定義放入類的根級別。 然後爲枚舉其列的每個表格創建內部類。
注:通過實現 BaseColumns 接口,您的內部類可繼承名爲 _ID 的主鍵字段,某些 Android 類(比如光標適配器)將需要內部類擁有該字段。 這並非必需項,但可幫助您的數據庫與 Android 框架協調工作。
例如,該代碼段定義了單個表格的表格名稱和列名稱:
public final class FeedReaderContract {
// To prevent someone from accidentally instantiating the contract class,
// make the constructor private.
private FeedReaderContract() {}
/* Inner class that defines the table contents */
public static class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
}
}
使用 SQL Helper創建數據庫
在您定義了數據庫的外觀後,您應實現創建和維護數據庫和表格的方法。 這裏有一些典型的表格創建和刪除語句:
private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
FeedEntry._ID + " INTEGER PRIMARY KEY," +
FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
FeedEntry.COLUMN_NAME_SUBTITLE + TEXT_TYPE + " )";
private static final String SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
就像您在設備的內部存儲中保存文件那樣,Android 將您的數據庫保存在私人磁盤空間,即關聯的應用。 您的數據是安全的,因爲在默認情況下,其他應用無法訪問此區域。
SQLiteOpenHelper 類中有一組有用的 API。當您使用此類獲取對您數據庫的引用時,系統將只在需要之時而不是應用啓動過程中執行可能長期運行的操作:創建和更新數據庫。 您僅需調用 getWritableDatabase() 或 getReadableDatabase() 即可。
注:由於它們可能長期運行,因此請確保您在後臺線程中調用 getWritableDatabase() 或 getReadableDatabase(),比如使用 AsyncTask 或 IntentService。
要使用 SQLiteOpenHelper,請創建一個替換 onCreate()、onUpgrade() 和onOpen() 回調方法的子類。您可能還希望實現 onDowngrade(),但這並非必需操作。
例如,下面是一個使用如上所示一些命令的 SQLiteOpenHelper 的實現:
public class FeedReaderDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.
public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = "FeedReader.db";
public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
}
要訪問您的數據庫,請實例化 SQLiteOpenHelper 的子類:
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
將信息存入數據庫
通過將一個 ContentValues 對象傳遞至 insert() 方法將數據插入數據庫:
// Gets the data repository in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();
// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_SUBTITLE, subtitle);
// Insert the new row, returning the primary key value of the new row
long newRowId = db.insert(FeedEntry.TABLE_NAME, null, values);
- 參數
- insert() 的第一個參數即爲表名稱。
- 第二個參數將指示框架在 ContentValues 爲空(即,您沒有傳任何值)時執行哪些操作。如果指定列名稱,則框架將插入一行並將該列的值設置爲 null。如果指定 null(就像此代碼示例中一樣),則框架不會在沒有值時插入行。
從數據庫讀取信息
要從數據庫中讀取信息,請使用 query() 方法,將其傳遞至選擇條件和所需列。該方法結合 insert() 和 update() 的元素,除非列 列表定義了您希望獲取的數據,而不是希望插入的數據。 查詢的結果將在 Cursor 對象中返回給您。
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Define a projection that specifies which columns from the database
// you will actually use after this query.
//projection是投影的意思,這裏意爲選擇哪些列的數據
String[] projection = {
FeedEntry._ID,
FeedEntry.COLUMN_NAME_TITLE,
FeedEntry.COLUMN_NAME_SUBTITLE
};
// Filter results WHERE "title" = 'My Title'
String selection = FeedEntry.COLUMN_NAME_TITLE + " = ?";
String[] selectionArgs = { "My Title" };
// How you want the results sorted in the resulting Cursor
String sortOrder =
FeedEntry.COLUMN_NAME_SUBTITLE + " DESC";
Cursor c = db.query(
FeedEntry.TABLE_NAME, // The table to query
projection, // The columns to return
selection, // The columns for the WHERE clause
selectionArgs, // The values for the WHERE clause
null, // don't group the rows
null, // don't filter by row groups
sortOrder // The sort order
);
要查看遊標中的某一行,請使用 Cursor 其中一個移動方法,您必須在開始讀取值之前始終調用這些方法。 一般情況下,您應通過調用 moveToFirst() 開始,其將“讀取位置”置於結果中的第一個條目中。 對於每一行,您可以通過調用 Cursor 獲取其中一個方法讀取列的值,比如 getString() 或 getLong()。對於每種獲取方法,您必須傳遞所需列的索引位置,您可以通過調用 getColumnIndex() 或 getColumnIndexOrThrow() 獲取。例如:
cursor.moveToFirst();
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
從數據庫中刪除信息
要從表格中刪除行,您需要提供識別行的選擇條件。 數據庫 API 提供了一種機制,用於創建防止 SQL 注入的選擇條件。 該機制將選擇規範劃分爲選擇子句和選擇參數。 該子句定義要查看的列,還允許您合併列測試。 參數是根據捆綁到子句的項進行測試的值。由於結果並未按照與常規 SQL 語句相同的方式進行處理,它不受 SQL 注入的影響。
// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { "MyTitle" };
// Issue SQL statement.
db.delete(FeedEntry.TABLE_NAME, selection, selectionArgs);
更新數據庫
當您需要修改數據庫值的子集時,請使用 update() 方法。
更新表可將 insert() 的內容值語法與 delete() 的 where 語法相結合。
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// New value for one column
ContentValues values = new ContentValues();
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
// Which row to update, based on the title
String selection = FeedEntry.COLUMN_NAME_TITLE + " LIKE ?";
String[] selectionArgs = { "MyTitle" };
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);