android数据库使用情景: 在android客户端,对于一些大量 复杂并且反复操作的数据,适合存储在数据库如同 通讯录信息。 而对于一些 简单数据如 标记 登录次数等 可以考虑用SharePreference。
(同样android底层还是运用基本的SQL语言操作数据库。 android数据库 API 在 android.database.sqlite包内)
第一步: 定义数据库的基本架构以及约定
为创建的数据库建立一个架构 --- 规范的声明 : 数据库的组织结构 数据库名 --- 表 ---- 字段(cloumn) 三重结构的每部分。
这个架构类几乎包含数据库中的所有常量,声明URIs的名字,表、列等基本结构。 这样做的效果可以使得在数据库操作的整个阶段共用这些常量,使得对于数据库字段等名字日后的修改变得简单,只需修改一处常量即可。
如何表示这三层结构呢? 类代表了数据库,类中的常量作为数据库全局的变量,使用内部类去代表数据库的每一个表格,内部类中常量代表各个字段。
android数据库中大多数地方要求有约定_ID主键,此时内部类通过继承BaseColumns接口,获得这个字段,使得你建立的数据库更加适应于android框架。
如下代码段,声明数据库以及该数据库中的一张表结构。
public final class FeedReaderContract {
// To prevent someone from accidentally instantiating the contract class,
// give it an empty constructor.
public FeedReaderContract() {}
/* Inner class that defines the table contents */
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";
...
}
}
第二步 建立数据库(使用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_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
... // Any other options for the CREATE command
" )";
private static final String SQL_DELETE_ENTRIES =
"DROP TABLE IF EXISTS " + FeedEntry.TABLE_NAME;
在android框架里SQLiteOpenHelper 类提供一系列简单快捷的数据库操作API。这就是数据库操作中的主角。
当你使用这个方法去获得对数据库的引用时,系统后台框架做了一些耗时的操作去创建或更新数据库,而不是默认直接在应用打开时获得。而你需要做的就是调用这个类的 getWritableDatabase()或是getReadableDatabase() 获得对于数据库引用,这样你应该把这个调用放到后台线程进行,比如AsyncTask或者IntentService中,而不是UI线程傻傻等待。
要使用SQLiteOpenHelper, 通过创建一个子类必须覆盖该类的onCreate(),onUpgrade()和onOpen()这些回调方法,和可覆盖的方法onDownGrad() (数据库回溯)
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());
所以真正创建过程在android框架中进行,我们只需调用mDbHelper.getWritableDatabase()方法,系统会回调相应的OnCreate或者onUpgrade方法执行相应的SQL语句创建数据库。同样这些操作会在 一块与你应用相关联的存储区域建立数据库文件 db 即 /data/data/包名/db 文件目录下。为了保证数据安全性,其他应用不能访问到这些文件。
第三步 数据库数据的数据操作:
android通过SQLiteDatabase提供封装好的数据库数据操作API。通过一些直接的参数,从而对数据库进行复杂操作。
1 数据的插入: 通过contentValues 类似键值对的对象作为载体(key为列名,value是插入的值),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_ENTRY_ID, id);
values.put(FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedEntry.COLUMN_NAME_CONTENT, content);
// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
FeedEntry.TABLE_NAME,
FeedEntry.COLUMN_NAME_NULLABLE,
values);
关于insert的第二个参数 代表 nullColumnHack ,可以为空,或者是一个列名,因为对于空的contentValues对象时,SQL语句插入时没有列名和值时,使得不能插入数据。
所以当你需要在value为空时,也能够插入一条空的记录,提供任意一个列名给这个方法。
2 读取数据
使用qury() 方法,传递查询条件和返回列 , 返回结果是一个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_UPDATED,
...
};
// How you want the results sorted in the resulting Cursor
String sortOrder =
FeedEntry.COLUMN_NAME_UPDATED + " 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对象后,要想查看到结果集行,必须先调用cursor的move方法移到某个位置进行读取。 一般使用moveToFirst()方法将读取位置对应于结果的首行。然后对于 每行,调用cursor的get方法获取列值如getString(int index),getLong(int index),其中参数代表了列的索引通过 getColumnIndex(columnName)获得。比如:
cursor.moveToFirst();
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
3 删除数据
你需要提供选择条件去删除特定的行。系统提供创建条件语句方法 以保证SQL语句的注入。这个方法 将选择条件分为 选择语句 和 选择参数俩部分。 选择语句声明选择的一列或者多列,而选择参数提供相应列的值。
// Define 'where' part of query.
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
// Specify arguments in placeholder order.
String[] selectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);
4 更新数据
使用update方法修改数据库中的子集。
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 ID
String selection = FeedEntry.COLUMN_NAME_ENTRY_ID + " LIKE ?";
String[] selectionArgs = { String.valueOf(rowId) };
int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);