安卓SQLite数据库所创建的数据是私有与所创建的应用程序。通过Content Provider给外接提供接口,从而其它的APP可以通过此来访问。
Content Provider基于一个简单的URI地址模型:使用 content:// 模式(schema). 它使你的应用程序层与数据层去耦合。
通常比较好的,你需要去封装一些公有的方法和常量作为与底层数据库交互的需要。通常封装到一个类中,而这种类通常称为XXContact或者XXHelper。
例子:片段
// The index (key) column name for use in where clauses. public static final String KEY_ID = “_id”;// The name and column index of each column in your database. // These should be descriptive. public static final String KEY_GOLD_HOARD_NAME_COLUMN = “GOLD_HOARD_NAME_COLUMN”; public static final String KEY_GOLD_HOARD_ACCESSIBLE_COLUMN = “OLD_HOARD_ACCESSIBLE_COLUMN”; public static final String KEY_GOLD_HOARDED_COLUMN = “GOLD_HOARDED_COLUMN”; // TODO: Create public field for each column in your table.
介绍SQLiteOpenHelper
SQLiteOpenHelper是一个抽象类,用来创建,打开,更新数据库。
通过实现这样一个抽象类,你可以隐藏你的逻辑是否一个数据库在打开前需要被创建或者更新,同时确保每个操作都是被有效得完成。
比较好的方式:推迟创建和打开数据库,直到他们需要的时候。
除非你不需要使用当前的SQLite数据库了,否则打开后就先不要关闭它。
注意:数据库操作,尤其是打开或者创建数据库是比较耗时的。为了确保用户体验,应该让所有的数据库事务都异步进行。
例子:实现SQLiteOpenHelper
private static class HoardDBOpenHelper extends SQLiteOpenHelper { private static final String DATABASE_NAME = “myDatabase.db”; private static final String DATABASE_TABLE = “GoldHoards”; private static final int DATABASE_VERSION = 1; // SQL Statement to create a new database. private static final String DATABASE_CREATE = “create table “ + DATABASE_TABLE + “ (“ + KEY_ID + “ integer primary key autoincrement, “ + KEY_GOLD_HOARD_NAME_COLUMN + “ text not null, “ + KEY_GOLD_HOARDED_COLUMN + “ float, “ + KEY_GOLD_HOARD_ACCESSIBLE_COLUMN + “ integer);”; public HoardDBOpenHelper(Context context, String name, CursorFactory factory, int version) { super(context, name, factory, version); } // Called when no database exists in disk and the helper class needs // to create a new one. @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DATABASE_CREATE); } // Called when there is a database version mismatch meaning that // the version of the database on disk needs to be upgraded to // the current version. @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { // Log the version upgrade. Log.w(“TaskDBAdapter”, “Upgrading from version “ + oldVersion + “ to “ + newVersion + “, which will destroy all old data”); // Upgrade the existing database to conform to the new // version. Multiple previous versions can be handled by // comparing oldVersion and newVersion values. // The simplest case is to drop the old table and create a new one. db.execSQL(“DROP TABLE IF IT EXISTS “ + DATABASE_TABLE); // Create a new one. onCreate(db); } }
在这个例子中,onUpgrade简单得删除了表,然后再重新创建。这是最简单和实用解决方式。但是,若一些重要数据无法通过网络同步,一个好的方式就是将存在的数据移植到新的表中。
程序中实用SQLiteHelper去获取一个数据库有2种方式:
1.getWritableDatabase 可读可写
2.getReadableDatabase 只读
如果数据库不存在,则helper类执行onCreate方法。如果数据库版本发生改变,则执行onUpgrade方法。
当数据库被成功打开,SQLiteHelper会缓存它,所以你可以随时对数据库进行操作。
不用SQLiteHelper去打开和创建数据库
如果你想直接去管理创建,打开和版本控制数据库.你可以使用APP的Context的openOrCreateDatabase方法,自己去创建数据库。
SQLiteDatabase db = context.openOrCreateDatabase(DATABASE_NAME,Context.MODE_PRIVATE, null);
通常比较好的方式:需要使用数据库的时候再去创建或者打开它,打开成功后然后缓存数据库实例,考虑到效率的问题。
最最少的,这些对数据库的操作都应该异步进行,不然可能会影响主APP进程。
安卓数据库设计考虑
1.文件(位图,视频文件)通常不直接存放在数据库表中。使用一个字符串去存储它的文件路径,更好的方式有一个完整合格的URI。
2.尽管不是严格的一个要求,通常还是强烈推荐所有的表都应该包含一个自动增长字段,作为每行的唯一索引字段。如果你计划通过Content Provider去共享你的表,这个唯一的ID字段就需要了。
查询数据库
每个数据库查询都返回一个Cursor。通过获取和释放行和列的值,这使安卓管理资源更加有效率。
查询数据库例子:
// Specify the result column projection. Return the minimum set // of columns required to satisfy your requirements. String[] result_columns = new String[] { KEY_ID, KEY_GOLD_HOARD_ACCESSIBLE_COLUMN, KEY_GOLD_HOARDED_COLUMN };// Specify the where clause that will limit our results. String where = KEY_GOLD_HOARD_ACCESSIBLE_COLUMN + “=” + 1;// Replace these with valid SQL statements as necessary. String whereArgs[] = null; String groupBy = null; String having = null; String order = null;SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); Cursor cursor = db.query(HoardDBOpenHelper.DATABASE_TABLE, result_columns, where, whereArgs, groupBy, having, order);从Cursor中提取值
使用moveTo<location>方法, 接着有getColumnIndexOrThrow和getColumnIndex,前者是若找不到该列会抛出异常,而后者:若返回的是-1,则表示该列不存在。
任何时候某列不存在,后者更有效些,例子:
int columnIndex = cursor.getColumnIndex(KEY_COLUMN_1_NAME); if (columnIndex > -1) { String columnValue = cursor.getString(columnIndex); // Do something with the column value. } else { // Do something else if the column doesn’t exist. }
注意:你应该提供数共有的数据库列名静态常量,就像我们之前提到的那样,通过Contract或者Helper类去封装,或者通过Content Provider。
从Curor中获取值 例子:
float totalHoard = 0f; float averageHoard = 0f;// Find the index to the column(s) being used. int GOLD_HOARDED_COLUMN_INDEX = cursor.getColumnIndexOrThrow(KEY_GOLD_HOARDED_COLUMN);// Iterate over the cursors rows. // The Cursor is initialized at before first, so we can // check only if there is a “next” row available. If the // result Cursor is empty this will return false. while (cursor.moveToNext()) { float hoard = cursor.getFloat(GOLD_HOARDED_COLUMN_INDEX); totalHoard += hoard; }// Calculate an average -- checking for divide by zero errors. float cursorCount = cursor.getCount();averageHoard = cursorCount > 0 ? (totalHoard / cursorCount) : Float.NaN;// Close the Cursor when you’ve finished with it. cursor.close();
注意:因为SQLite数据库是弱类型的,所以你获取值的时候,比如上述值是float型的,你也可以获取字符串型的。
当你完成一个查询,非常重要的一点:关掉Cursor避免内存泄露和减少你的APP资源加载。
cursor.close();
增加,更新,和移除行
SQLiteDatabase类还有insert,delete和update方法。
1.insert
首先你需要构建一个ContentValue对象,put方法去放入每列对应的值,这里的键就是列名。从而构建一行的数据,然后再插入。
看例子:
// Create a new row of values to insert. ContentValues newValues = new ContentValues();// Assign values for each row. newValues.put(KEY_GOLD_HOARD_NAME_COLUMN, hoardName); newValues.put(KEY_GOLD_HOARDED_COLUMN, hoardValue); newValues.put(KEY_GOLD_HOARD_ACCESSIBLE_COLUMN, hoardAccessible); // [ ... Repeat for each column / value pair ... ]// Insert the row into your table SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); db.insert(HoardDBOpenHelper.DATABASE_TABLE, null, newValues);
注意:insert的第2个参数:如果你想向数据库插入一行空的数据,除了传一个空的ContentValue外,你还必须传递一个需要被显式置为空值的列名。
但是呢,通常最好的方式是你尽量避免去插入一个空的Content Value到SQLite数据库中,所以呢,这个第2个参数通常也就为null了。
2.update行
同样,你也需要一个Content Value对象去指定键/值对去更新指定列的值。
代码片段:
// Create the updated row Content Values. ContentValues updatedValues = new ContentValues();// Assign values for each row. updatedValues.put(KEY_GOLD_HOARDED_COLUMN, newHoardValue); // [ ... Repeat for each column to update ... ]// Specify a where clause the defines which rows should be // updated. Specify where arguments as necessary. String where = KEY_ID + “=” + hoardId; String whereArgs[] = null;// Update the row with the specified index with the new values. SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); db.update(HoardDBOpenHelper.DATABASE_TABLE, updatedValues, where, whereArgs);3.delete行
只需要指定表名和一个where语句。
代码片段:
// Specify a where clause that determines which row(s) to delete. // Specify where arguments as necessary. String where = KEY_GOLD_HOARDED_COLUMN + “=” + 0; String whereArgs[] = null;// Delete the rows that match the where clause. SQLiteDatabase db = hoardDBOpenHelper.getWritableDatabase(); db.delete(HoardDBOpenHelper.DATABASE_TABLE, where, whereArgs);