zoukankan      html  css  js  c++  java
  • SQLite cursor.moveToNext()

    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.SQLiteCursorgetCount()时,当前线程会锁定数据库,在该操作完成后才解锁。

    其调用关系如下
    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) 
    如果是第一次调用SQLiteCursorgetCount()的话,在getCount()中,它会调用fillWindow(),
    在SQLiteCursor的fillWindow()中,它又会调用SQLiteQueryfillWindow()
    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();
            } 
        }
    SQLiteQueryfillWindow()中,它首先需要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();
            }
        }
     
    结束!
  • 相关阅读:
    时间戳(UnixTimestamp)与 《2038年问题》
    端口相关命令
    Ubuntu中的在文件中查找和替换命令
    A Reusable Aspect for Memory Profiling
    acc文件的运行
    A Reusable Aspect for Memory Allocation Checking
    ACC常用语句
    aspectC++常用命令
    c++调用DOS命令,不显示黑屏
    fopen文件目录问题
  • 原文地址:https://www.cnblogs.com/littlezan/p/3783815.html
Copyright © 2011-2022 走看看