cursor.moveToNext()會出異常,以下
html
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)java
解決辦法,調用cursor.getCount().android
緣由大概以下:sql
當咱們第一調用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();
}
}
結束!