當我們第一調用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()android.database.sqlite.SQLiteCursor的相關源碼如下:
@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資料庫。android.database.sqlite.SQLiteQuery的相關源碼如下:/** * 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(); } }
結束!