cursor.moveToNext()会出异常,如下
E/AndroidRuntime( 2249): FATAL EXCEPTION: Thread-49
E/AndroidRuntime(
2249): java.lang.IllegalStateException: Cannot perform this operation because
the connection pool has been closed.
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteConnectionPool.throwIfClosedLocked(SQLiteConnectionPool.java:962)
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteConnectionPool.waitForConnection(SQLiteConnectionPool.java:599)
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteConnectionPool.acquireConnection(SQLiteConnectionPool.java:348)
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteSession.acquireConnection(SQLiteSession.java:894)
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteSession.executeForCursorWindow(SQLiteSession.java:834)
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:62)
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:143)
E/AndroidRuntime( 2249): at
android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:133)
E/AndroidRuntime( 2249): at
android.database.AbstractCursor.moveToPosition(AbstractCursor.java:197)
E/AndroidRuntime( 2249): at
android.database.AbstractCursor.moveToNext(AbstractCursor.java:245)
解决办法,调用cursor.getCount().
原因大概如下:
当我们第一调用android.database.sqlite.SQLiteCursor的getCount()时,当前线程会锁定数据库,在该操作完成后才解锁。
其调用关系如下:
at android.database.sqlite.SQLiteQuery.native_fill_window(Native
Method)
at
android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:73)
at
android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:287)
at
android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:268)
at
android.widget.CursorAdapter.getCount(CursorAdapter.java:132)
如果是第一次调用SQLiteCursor的getCount()的话,在getCount()中,它会调用fillWindow(),
在SQLiteCursor的fillWindow()中,它又会调用SQLiteQuery的fillWindow()
@Override
public int getCount() {
if (mCount == NO_COUNT)
{
fillWindow(0);
}
return mCount;
}
private void fillWindow
(int startPos) {
if (mWindow == null)
{
// If there isn‘t a window set
already it will only be accessed locally
mWindow = new CursorWindow(true
/* the window is local only */);
} else {
mCursorState++;
queryThreadLock();
try {
mWindow.clear();
} finally {
queryThreadUnlock();
}
}
mWindow.setStartPosition(startPos);
mCount = mQuery.fillWindow(mWindow,
mInitialRead, 0);
// return -1 means not finished
if (mCount ==
NO_COUNT){
mCount = startPos +
mInitialRead;
Thread t = new Thread(new
QueryThread(mCursorState), "query thread");
t.start();
}
}
在SQLiteQuery的fillWindow()中,它首先需要lock数据库,然后调用JNI层的native_fill_window()进行数据库操作,在其操作完成之后才unlock数据库。
/**
* Reads rows into a buffer. This method acquires
the database lock.
*
* @param window The window to fill
into
* @return number of total rows in the
query
*/
int fillWindow(CursorWindow
window,
int maxRead, int lastPos)
{
long timeStart =
SystemClock.uptimeMillis();
mDatabase.lock();
mDatabase.logTimeStat(mSql, timeStart,
SQLiteDatabase.GET_LOCK_LOG_PREFIX);
try {
acquireReference();
try {
window.acquireReference();
// if the
start pos is not equal to 0, then most likely window is
// too small
for the data set, loading by another thread
// is not
safe in this situation. the native code will ignore maxRead
int numRows
= native_fill_window(window, window.getStartPosition(),
mOffsetIndex,
maxRead, lastPos);
//
Logging
if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
Log.d(TAG, "fillWindow(): " + mSql);
}
mDatabase.logTimeStat(mSql, timeStart);
return
numRows;
} catch (IllegalStateException e){
// simply
ignore it
return 0;
} catch (SQLiteDatabaseCorruptException e) {
mDatabase.onCorruption();
throw e;
} finally {
window.releaseReference();
}
} finally {
releaseReference();
mDatabase.unlock();
}
}
结束!
SQLite cursor.moveToNext(),布布扣,bubuko.com
SQLite cursor.moveToNext()