定义schema和contract
SQL数据库的一个主要原则就是它的schema:数据库组织方式的正式声明。scheme反映在创建数据库的语句当中。
可以创建一个contract类来协助数据库的创建,一个contract类包含了可复用的URIs、数据表和数据栏的常量定义。组织一个contract类的好做法是把对于整个数据库生效的定义放到类成员变量中,然后为每个数据表创建一个内部类。
contract的内部类通过实现BaseColumns这个接口可以继承_ID这个常量,使用指针适配器要求有这个常量。虽然不是必须实现这个接口,但是实现的话有助于和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 SQL_CREATE_ENTRIES =
"CREATE TABLE " + FeedEntry.TABLE_NAME + " (" +
FeedEntry._ID + " INTEGER PRIMARY KEY," +
FeedEntry.COLUMN_NAME_TITLE + " TEXT," +
FeedEntry.COLUMN_NAME_SUBTITLE + " TEXT)";
private static final String SQL_DELETE_ENTRIES = "DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
数据库保存在应用的私有内部存储空间中,所以数据是安全的。
使用SQLiteOpenHelper获取数据库的引用,系统会在需要时运行打开或者升级数据库的耗时操作,操作不会在应用启动时进行。我们只需要调用getWritableDatabase() or getReadableDatabase()即可,但是因为可能是耗时操作,所以需要在子线程中运行,可以使用AsyncTask或者IntentService。
使用SQLiteOpenHelper需要创建其子类,复写onCreate(), onUpgrade() 和onOpen()三个回调。
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);
}
}
使用:
FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());
保存到数据库
// 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为空时(没有put数据进去),不会插入新数据。第二个参数指明某个栏时,会插入一条该栏为null的新数据。
从数据库获取信息
调用query()方法,返回一个Cursor
SQLiteDatabase db = mDbHelper.getReadableDatabase();
// Define a projection that specifies which columns from the database
// you will actually use after this query.
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 cursor = 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:调用moveToNext()方法移动指针。cursor.getString()或者getLong()等方法查询数据,传入所查询数据的index,可以使用cursor.getColumnIndex()或者cursor.getColumnIndexOrThrow()方法获取index。
List itemIds = new ArrayList<>();
while(cursor.moveToNext()) {
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedEntry._ID));
itemIds.add(itemId);
}
cursor.close();
从数据库中删除信息
要从数据库中删除一条数据,需要指明区分出该条数据的筛选条件。数据库API提供了一种避免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);
数据库升级
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);
数据库连接持久使用
因为 getWritableDatabase()和getReadableDatabase()调用比较耗时,所以应该尽量在需要使用时保持数据库的开启状态,比如在使用到数据库的Activity的onDestroy()中
@Override
protected void onDestroy() {
mDbHelper.close();
super.onDestroy();
}