SQLite为Android提供了关系数据库功能
所有的数据库存储在设备的/data/data/<package_name>/databases文件夹下
一、SQLite简介
SQLite是关系数据库管理系统(RDBMS),特点是:
开源
兼容标准
轻量级
Single-tier
实现为一简洁的C库,包含在Android软件栈中
作为应用程序的一部分而提供功能,这样可减少应用程序的外部依赖、最小化延迟并简化事务锁和同步。
与其它数据引擎区别的是,从每一行的第一列中分配或提取值时,不需要进行严格的类型检查
二、Cursor和内容值
用ContentValues 对象向数据库中插入一行,它代表一行,列名用于对它值的映射
Cursor对象
Cursor对象中的功能来操作导航结果:
● moveToFirst
●moveToNext
●moveToPrevious
●getCount
●getColumnName
●getColumnNames
●getColumnIndexOrThrow
●moveToPosition
●getPosition
startManagerCursor方法管理活动中的Cursor资源
三、使用Android数据库
创建一个helper类来简化对数据库的交互
Android中的一个标准数据库adapter类的框架:包含对SQLiteOpenHelper类的扩展
1: import android.content.ContentValues;
2: import android.content.Context;
3: import android.database.*;
4: import android.database.sqlite.*;
5: import android.database.sqlite.SQLiteDatabase.CursorFactory;
6: import android.util.Log;
7:
8: public class MyDBAdapter {
9: private static final String DATABASE_NAME = "myDatabase.db";
10: private static final String DATABASE_TABLE = "mainTable";
11: private static final int DATABASE_VERSION = 1;
12:
13: // where子句中使用的索引(键)列的名字
14: public static final String KEY_ID = "_id";
15:
16: // 数据库中的第一列的名称和索引
17: public static final String KEY_NAME = "name";
18: public static final int NAME_COLUMN = 1;
19: // 待实现,为你的表中的第一列创建公共域
20:
21: // 创建一个数据库的sql语句
22: private static final String DATABASE_CREATE = "create table " +
23: DATABASE_TABLE + " (" + KEY_ID +
24: " integer primary key autoincrement, " +
25: KEY_NAME + " text not null);";
26:
27: // 保存数据库实例的变量
28: private SQLiteDatabase db;
29: //使用数据库的应用程序的上下文
30: private final Context context;
31: // 数据库打开\更新helper类
32: private myDbHelper dbHelper;
33:
34: public MyDBAdapter(Context _context) {
35: context = _context;
36: dbHelper = new myDbHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
37: }
38: public MyDBAdapter open() throws SQLException {
39: db = dbHelper.getWritableDatabase();
40: return this;
41: }
42:
43: public void close() {
44: db.close();
45: }
46:
47: public long insertEntry(MyObject _myObject) {
48: ContentValues contentValues = new ContentValues();
49: // 待实现:填充ContentValues来表示新的行
50: return db.insert(DATABASE_TABLE, null, contentValues);
51: }
52:
53: public boolean removeEntry(long _rowIndex) {
54: return db.delete(DATABASE_TABLE, KEY_ID + "=" + _rowIndex, null) > 0;
55: }
56:
57: public Cursor getAllEntries () {
58: return db.query(DATABASE_TABLE, new String[] {KEY_ID, KEY_NAME},
59: null, null, null, null, null);
60: }
61:
62: public MyObject getEntry(long _rowIndex) {
63: MyObject objectInstance = new MyObject();
64: // 待实现,从数据库中返回一个行的Cursor,并使用该行的
65: // 值填充一个MyObject实例
66: return objectInstance;
67: }
68:
69: public int updateEntry(long _rowIndex, MyObject _myObject) {
70: String where = KEY_ID + " = " + _rowIndex;
71: ContentValues contentValues = new ContentValues();
72: // 待实现,根据新的对象填充ContentValues
73: return db.update(DATABASE_TABLE, contentValues, where, null);
74: }
75:
76: private static class myDbHelper extends SQLiteOpenHelper {
77:
78: public myDbHelper(Context context, String name, CursorFactory factory, int version) {
79: super(context, name, factory, version);
80: }
81:
82: // 当磁盘上没数据库时候调用,helper需要创建
83: // 一个新的数据库
84: @Override
85: public void onCreate(SQLiteDatabase _db) {
86: _db.execSQL(DATABASE_CREATE);
87: }
88:
89: // 当存储数据库不匹配时调用,也就是说,
90: // 磁盘上的数据库版本需要更新到当前版本
91: @Override
92: public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion) {
93: // 日志中记录数据库版本更新
94: Log.w("TaskDBAdapter", "Upgrading from version " +
95: _oldVersion + " to " +
96: _newVersion + ", which will destroy all old data");
97:
98: // 更新现有数据库,使其为最新版本
99: // 通过比较_oldVersion和_newVersion 值来处理多个以前的版本
100: // 最简单的情况是删除旧的表,创建一个新表
101:
102: //
103: _db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
104: // 创建一个新表
105: onCreate(_db);
106: }
107: }
1: dbHelper = new myDbHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
2:
3: SQLiteDatabase db;
4: try {
5: db = dbHelper.getWritableDatabase();
6: } catch (SQLiteException ex) {
7: db = dbHelper.getWritableDatabase();
8: }
针对数据库不存在时helper调用onCreate处理;版本改变时onUpgrade会触发.对于这两种情况,get<Write/read>Database返回已经存在、新创建的和更新过的数据库。
2、不使用SQLiteOpenHelper打开和创建数据库
调用openOrCreateDatabase
myDatabase = openOrCreateDatabase(DATABASE_NAME,Context.MODE_PRIVATE,null);
myDatabase.execSQL(DATABASE_CREATE);
3.Android数据库设计注意事项
(1)表中不存储文件,只存储使用完全限定的内容提供器URI来表示的路径
(2)表中应该包含一个自动增加的键域,为第一行提供唯一索引
4、查询数据库
查询返回一个结果集的Cursor
query方法原型(还有其它方法签名):
public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
参数:
●boolean distinct:是否包含唯一的值
●String table:查询表的名称
●String[] columns:列出包含在结果中列的字符串数组
●String selection:“where”子句,要返回的行。包含“?”将被选择参数中的值替换
●String[] selectionArgs:选择参数字符串数组,替换“where”子句中的“?”
●String groupBy:定义返回行的分组方式
●String having:过滤器,如果包含groupBy,则定义包含哪些行的分组
●String orderBy:行的顺序
●String limit:定义对返回行的限制
●CancellationSignal cancellationSignal
返回一个特定表中部分或全部的行的代码框架:
//返回第一列和第三列的所有行,没重复
String[] result_columns = new String{}[KEY_ID,KEY_COL1,KEY_COL3];
Cursor allRows = myDatabase.query(true,DATABASE_TABLE,result_columns,null,null,null,null,null,null);
//返回第三列中等于一个特定值的所有列,并按第5列排序
String where = KEY_COL3 + "=" + requiredValue;
String order = KEY_COL5;
Cursor myResult = myDatabase.query(DATABASE_TABLE,null,where,null,null,null,order);
5.从Cursor中提取结果
首先在返回的结果集Cursor中定位行moveTo<location>
get方法
String columnValue = myResult.getString(columnIndex);
6 、添加、更新和删除行
SQLiteDatabase类提供insert delete update等基本数据库操作方法,execSQL方法提供操作数据的有效方法
视图的Cursor的refreshQuery方法将对底层数据的修改进行提交。
(1)插入一个新行
构建ContentValues对象,put方法为列提供值,用instert插入数据库
1: //创建要插入一个新行
2: ContentVlaues newValues = new ContentValues();
3: //为每行赋值
4: newValues.put(COLUMN_NAME,newVlaue);
5: [...Repeat for each colum...]
6: //把行插入到表中
7: myDatabase.insert(DATABASE_TABLE,null,newValues);
(2)更新数据库中的行
//定义要更新的新行
ContentVlaues updatedValues = new ContentValues();
//为每行赋值
updatedValues.put(COLUMN_NAME,newVlaue);
[...Repeat for each colum...]
String where = KEY_ID + "=" + rowID;
//使用新的值更新指定索引的行
myDatabase.update(DATABASE_TABLE,updatedValues,where,null);
//把行插入到表中
myDatabase.insert(DATABASE_TABLE,null,newValues);
(3)删除行
myDatabase.delete(DATABASE_TABLE,KEY_ID + "=" +rowId,null);
将前面的To-Do List改进,创建一个私有的数据库来保存待办事项.
(1)首先创建一个新的ToDoDBAdapter类。
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;
/** Database Adapter for persisting Todo Items */
public class ToDoDBAdapter {
private static final String DATABASE_NAME = "todoList.db";
private static final String DATABASE_TABLE = "todoItems";
private static final int DATABASE_VERSION = 1;
private SQLiteDatabase db;
private final Context context;
public ToDoDBAdapter(Context _context) {
context = _context;
}
(2)定义列的名称和索引,从查询返回的Cursor中查询到正确的列
public static final String KEY_ID = "_id";
public static final String KEY_TASK = "task";
public static final String KEY_CREATION_DATE = "creation_date";
public static final int TASK_COLUMN = 1;
public static final int CREATION_DATE_COLUMN = 2;
(3)创建taskDBOpenHelper,它扩展了SQLiteOpenHelper.类中,重写onCreate和onUpgrade处理数据库的创建和更新逻辑
1: private static class toDoDBOpenHelper extends SQLiteOpenHelper {
2:
3: public toDoDBOpenHelper(Context context, String name, CursorFactory factory, int version) {
4: super(context, name, factory, version);
5: }
6:
7: /** 创建一个新数据库的SQL语句*/
8: private static final String DATABASE_CREATE = "create table " +
9: DATABASE_TABLE + " (" + KEY_ID + " integer primary key autoincrement, " +
10: KEY_TASK + " text not null, " + KEY_CREATION_DATE + " integer);";
11:
12: @Override
13: public void onCreate(SQLiteDatabase _db) {
14: _db.execSQL(DATABASE_CREATE);
15: }
16:
17: @Override
18: public void onUpgrade(SQLiteDatabase _db, int _oldVersion, int _newVersion) {
19: Log.w("TaskDBAdapter", "Upgrading from version " +
20: _oldVersion + " to " +
21: _newVersion + ", which will destroy all old data");
22:
23: // Drop the old table.
24: _db.execSQL("DROP TABLE IF EXISTS " + DATABASE_TABLE);
25: // Create a new one.
26: onCreate(_db);
27: }
28: }
(4)创建toDoDBOpenHelper类的一个实例,构造函数中为它赋值
1: private toDoDBOpenHelper dbHelper;
2:
3: public ToDoDBAdapter(Context _context) {
4: context = _context;
5: dbHelper = new toDoDBOpenHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
6: }
(5)close方法
/** Close the database */
public void close() {
db.close();
}
(6)open方法用到toDoDBOpenHelper类,getWritableDatabase创建数据库和版本检查
/** Open the database */
public void open() throws SQLiteException {
try {
db = dbHelper.getWritableDatabase();
}
catch (SQLiteException ex) {
db = dbHelper.getReadableDatabase();
}
}
(7)添加、删除和修改条目
1: /** 插入一个新的任务*/
2: public long insertTask(ToDoItem _task) {
3: // 创建要插入的一行新值
4: ContentValues newTaskValues = new ContentValues();
5:
6: // 为每一行赋值
7: newTaskValues.put(KEY_TASK, _task.getTask());
8: newTaskValues.put(KEY_CREATION_DATE, _task.getCreated().getTime());
9:
10: // 插入行
11: return db.insert(DATABASE_TABLE, null, newTaskValues);
12: }
13:
14: /** 根据索引删除一个任务*/
15: public boolean removeTask(long _rowIndex) {
16: return db.delete(DATABASE_TABLE, KEY_ID + "=" + _rowIndex, null) > 0;
17: }
18:
19: /** 更新一个任务 */
20: public boolean updateTask(long _rowIndex, String _task) {
21: ContentValues newValue = new ContentValues();
22: newValue.put(KEY_TASK, _task);
23: return db.update(DATABASE_TABLE, newValue, KEY_ID + "=" + _rowIndex, null) > 0;
24: }
(8)用helper方法查询:3个方法:
a、返回所有条目;b、作为一个Cursor返回特定行;c、返回一个强类型ToDoItem
/** Return a Cursor to all the Todo items */ public Cursor getAllToDoItemsCursor() { return db.query(DATABASE_TABLE, new String[] { KEY_ID, KEY_TASK, KEY_CREATION_DATE}, null, null, null, null, null); } /** Return a Cursor to a specific row */ public Cursor setCursorToToDoItem(long _rowIndex) throws SQLException { Cursor result = db.query(true, DATABASE_TABLE, new String[] {KEY_ID, KEY_TASK}, KEY_ID + "=" + _rowIndex, null, null, null, null, null); if ((result.getCount() == 0) || !result.moveToFirst()) { throw new SQLException("No Todo items found for row: " + _rowIndex); } return result; } /** Return a Todo Item based on its row index */ public ToDoItem getToDoItem(long _rowIndex) throws SQLException { Cursor cursor = db.query(true, DATABASE_TABLE, new String[] {KEY_ID, KEY_TASK}, KEY_ID + "=" + _rowIndex, null, null, null, null, null); if ((cursor.getCount() == 0) || !cursor.moveToFirst()) { throw new SQLException("No to do item found for row: " + _rowIndex); } String task = cursor.getString(TASK_COLUMN); long created = cursor.getLong(CREATION_DATE_COLUMN); ToDoItem result = new ToDoItem(task, new Date(created)); return result; }