在需要处理大量列表数据的App里面,比如IM、电商、新闻等都会使用DB来存储底层数据,确切的说如果App需要处理大量重复类型的数据,一般都会选择使用 DB配合CursorAdapter来实现。Android自带的数据库是SQLite 一个简单的基于文件的嵌入式DB。
在SQL数据库中必须定义数据库的结构(Scheme)也就是数据库名字、表和表结构这些东西。Android文档推荐定义一个Contract类,来全局管理数据
库常量,在Contract类中再通过静态内部类定义表和表的结构。定义表结构的内部类,推荐实现BaseColumns 
接口,它在内部定义了 _COUNT 和 _ID(主键) 两个列(CursorAdapter需要实现这个接口)。
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语法
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;
SQLiteOpenHelper 类封装了数据库的创建和销毁,我们可以重载这个类的某些方法来创建数据库并提供便捷的操作接口。
使用这个类来操作数据库的好处是数据库不会在App启动的时候立即被创建,而是在适当的时候创建。操作数据库需要调用 getWritableDatabase() 和 getReadableDatabase() 
方法来获取 SQLiteDatabase 类实例,它会提供数据库的增删改查方法。这两个方法的调用可能会耗时长久,最好在异步线程中调用,避免阻塞主线程。
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);
    }
}
SQLiteDatabase类提供了数据库的增删改查方法,往数据库中添加数据可以编辑SQL语句来完成,也可以通过 ` ContentValues` 类,这个类提供了K-V的方式来组织待插入的数据,key是数据库的列,
value是这一列的值。
// 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);
删除某一行,需要先选定这一行, SQLiteOpenHelper 类提供的选择方式是把选择分成两部分选择语句和选择条件。这种模式在查找和修改
的时候都会用到。
// 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);
改动和删除无异只是多了一个参数 ContentValues
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);
查找还是比较复杂的,需要确定6个参数,最后会返回一个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
    );
6个参数分别是
函数的返回结果是一个Curor类,Curso类提供一些迭代的方法来遍历选择结果。需要先调用 moveToFirst() 方法让迭代器指向数据
开始的位置,然后通过 ` getString() 和 getLong()` 等类似方法来取回查找结果。
cursor.moveToFirst();
long itemId = cursor.getLong(
    cursor.getColumnIndexOrThrow(FeedEntry._ID)
);
内容来自Android文档:
nTop 19 January 2015