最近开发的一个功能会用到SQLite,碰到一个问题,纠结了整整一个下午,终于找到原因,记录一下。
功能很简单,创建了一个自定义的ListView,在每个ListView中都对应有一个Button,而该Button需要有个状态记录Button使用情况,比如Enable和Disable。顺利地创建了数据库和自定义ListView,在点击Button时,将ListView对应的信息通过setTag(key, value)传递,并在Button的onClick()中通过getTag(key)获得对应属性。以上步骤暂时都未碰到任何问题,接下来问题就来了。
在SQLiteOpenHelper的继承类DataBaseProvider中,增加了一个查询数据记录的函数,代码如下:
public Cursor query(String name) {
SQLiteDatabase db = this.getReadableDatabase();
String querySql = "select " + PKG_NAME + " , " + CMP_STATE + " from " + TABLE_APPS_NAME + " where " +
CMP_NAME + " = '" + compName + "'";
Cursor cursor = db.rawQuery(querySql, null);
return cursor;
}
在反复跟踪这段代码时,发现得到的Cursor对象值总有问题,数据内容老是对应的database中table的Column名,未得到正确的database record。百思不得其解,对应地也查找了Android工程中其他数据库查询的操作,也大同小异,最后检查下来才发现,在rawQuery结束后,需要将cursor定位到record的起始位置,即需要再调用一下cursor.moveToFirst()。最新代码更新如下:
public Cursor query(String name) {
SQLiteDatabase db = this.getReadableDatabase();
String querySql = "select " + PKG_NAME + " , " + CMP_STATE + " from " + TABLE_APPS_NAME + " where " +
CMP_NAME + " = '" + compName + "'";
Cursor cursor = db.rawQuery(querySql, null);
cursor.moveToFirst();
return cursor;
}
到这里,数据库功能上的问题已经解决了,但是作为有专研精神的码农怎么能放过Discovery的好机会呢?那么我们从SQLiteDatabase的rawQuery接口开始分析,码农比较习惯以文件名来划分步骤:
1、SQLiteDatabase.java
public Cursor rawQuery(String sql, String[] selectionArgs,
CancellationSignal cancellationSignal) {
return rawQueryWithFactory(null, sql, selectionArgs, null, cancellationSignal);
}
显然,rawQuery(......)又调用了rawQueryWithFactory(......),函数如下:
public Cursor rawQueryWithFactory(
CursorFactory cursorFactory, String sql, String[] selectionArgs,
String editTable, CancellationSignal cancellationSignal) {
acquireReference();
try {
SQLiteCursorDriver driver = new SQLiteDirectCursorDriver(this, sql, editTable,
cancellationSignal);
return driver.query(cursorFactory != null ? cursorFactory : mCursorFactory,
selectionArgs);
} finally {
releaseReference();
}
}
从代码看,是先创建了一个SQLiteDirectCursorDriver实例,并由该实例driver来执行query(...)。
2、SQLiteDirectCursorDriver.java
public Cursor query(CursorFactory