保存數據到數據庫中是理想的重復或者結構化數據的方式。例如聯系人信息。這節課程假設你熟悉通常的SQL數據庫,並幫助你開始在Android中的SQLite數據庫。在android.database.sqlite包中的API,你將需要使用一個在Android平台有效的數據庫。
定義一個模式和契約
—————————————————————————————————————————————————————————————————
SQL數據庫一個主要原則是這個模式:數據庫是如何被組織的一個正式說明。這個模式被映射到你用來創建你的數據庫的SQL語句。你會發現它有助於創建一個相關類,被稱為一個契約類,它明確指定了你的模式在系統和自定義方式中的布局。
一個契約類是一個常量容器,它定義了URIs的名字,表,和列。這個常量類允許你在同樣的包中的所有其它類使用同樣的常量。這讓你在一個地方改變列的名稱和通過你的代碼有它的聲明。
組織一個契約類的好的方式是使定義對於你整個數據根級別的類是全局的。然後為每個列舉它的列的表創建一個內部類。
注意:通過實現BaseColumns接口,你的內部類能繼承一個被稱為_ID私有的鍵域,一些Android類如游標適配器將會期望擁有它。它不是必須的,但是它能幫助你的數據庫在Android框架中和諧的工作。
例如,這個代碼塊定義了一個單獨表的表名和列名:
[java]
public static abstract class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = "entry";
public static final String COLUMN_NAME_ENTRY_ID = "entryid";
public static final String COLUMN_NAME_TITLE = "title";
public static final String COLUMN_NAME_SUBTITLE = "subtitle";
...
}
為了阻止其它人無意的實例化這個契約類,給它一個空的構造器。
[java]
// Prevents the FeedReaderContract class from being instantiated.
private FeedReaderContract() {}
使用一個SQLHelper類創建一個數據庫
——————————————————————————————————————————————
一旦你定義了你的數據的外貌,你應該實現創建和維護數據庫和表的方法。下面是一些典型的聲明,創建和刪除一個表:
[java] view plaincopy
private static final String TEXT_TYPE = " TEXT";
private static final String COMMA_SEP = ",";
private static final String SQL_CREATE_ENTRIES =
"CREATE TABLE " + FeedReaderContract.FeedEntry.TABLE_NAME + " (" +
FeedReaderContract.FeedEntry._ID + " INTEGER PRIMARY KEY," +
FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
... // Any other options for the CREATE command
" )";
private static final Str_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + TABLE_NAME_ENTRIES;
正如你保存在設備的內部存儲的文件,Andrid保存你的數據庫在一個和應用程序相關的私有的硬盤空間。你的數據是安全的,因為默認情況下這個空間對於其它應用程序是不能訪問的。
在SQLiteOpenHelter類中有一個可利用的API集合。當你使用這個類來獲取你的數據庫引用的時候,僅僅當需要和不是應用程序啟動的時候,系統執行執行隱藏的長時間操作來創建和更新數據庫。所有你需要做的是調用getWritableDatabase()方法或者getReadableDatabase()方法。
注意:因為他們長時間運行,確保你在後台線程調用getWritableDtabase()方法或者getReadableDatabase()方法,例如使用AsyncTask或者IntentService。
為了使用SQLiteOpenHelper,創建一個子類,它覆蓋了onCreate()方法,onUpgrade()方法和onOpen()回調方法。你也可能想實現onDowngrade()方法,但是它不是必須的。
例如,這裡是SQLiteOpenHelper的一個實現,它使用了上面顯示的一些命令:
[java]
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子類:
[java]
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
將信息保存到一個數據庫中
————————————————————————————————————————————————————————————————
通過傳遞一個ContentValues對象給insert()方法來向數據庫中插入數據:
[java]
// 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(FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, content);
// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
FeedReaderContract.FeedEntry.TABLE_NAME,
FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE,
values);
inSert()方法的第一個參數表名。第二個參數提供了一個列的名稱,在ContentValues是空的情況下,框架可以插入NULL(如果你替代設置這個值為“null”,那麼框架將不會插入一行,當沒有數據的時候)。
從一個數據庫中讀取數據
——————————————————————————————————————————————
為了讀取一個數據庫,使用query()方法,給它傳遞你的選擇條件和期望的列。這個方法聯合insert()和update()方法的元素,除了定了你想獲取的數據的列列表,而不是插入的數據。查詢返回給你的結果是一個Cursor對象。
[java]
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
FeedReaderContract.FeedEntry._ID,
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE,
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED,
...
};
// How you want the results sorted in the resulting Cursor
String sortOrder =
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED + " DESC";
Cursor c = db.query(
FeedReaderContract.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對象的一個get方法來讀取一個列的值,例如getString()方法或者getLong()方法。對於每個get方法,你必須傳遞你期望的列的索引位置,它可以通過調用getColunIndex()或者getColunIndexOrThrow()方法獲取。例如:
[java]
cursor.moveToFirst();
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID)
); <span style="background-color:transparent; color:windowtext; font-family:'Calibri Light',sans-serif; font-size:10pt; line-height:16px"> </span>
從一個數據庫中刪除數據
——————————————————————————————————————————————
為了從一個表中刪除行,你需要提供識別行的選擇條件。數據庫API提供了一種機制來創建選擇條件,保護違反SQL注入。這個機制分配選擇規格到一個選擇子句和選擇參數。子句定義了查看的列,並且也允許你聯合列測試。參數測試違反,它被綁定到子句中。因為結果和一個通常的SQL語句處理不同,它避免了SQL注入。
[java]
// Define 'where' part of query.
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
String[] selelectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);
更新一個數據庫
——————————————————————————————————————————————
當你需要修改你的數據庫的一直子集的值的時候,使用update()方法。
更新表聯合insert()值語法格式和delete()where語法格式。
[java]
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// New value for one column
ContentValues values = new ContentValues();
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
// Which row to update, based on the ID
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selelectionArgs = { String.valueOf(rowId) };
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);