java.lang.IllegalStateException:尝试重新打开已经关闭的对象:SQLiteQuery

时间:2015-06-06 09:43:57

标签: java android

所以我有这个奇怪的错误。我使用简单的游标适配器来建议searchView和数据库。我不需要内容提供商,所以我没有使用它。问题是我没有在我的代码中的任何地方关闭我的数据库或光标的命令,但我仍然收到此错误。 错误:

    java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteQuery: SELECT _id as _id, title as suggest_text_1, subTitle as suggest_text_2, imgUrl as suggest_icon_1, searchID as suggest_intent_data_id FROM suggestions WHERE (title like ? ) ORDER BY title asc  LIMIT 10
        at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
        at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:58)
        at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:152)
        at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:124)
        at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:214)
        at android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:225)
        at android.widget.AdapterView.rememberSyncState(AdapterView.java:1199)
        at android.widget.AdapterView$AdapterDataSetObserver.onChanged(AdapterView.java:815)
        at android.widget.AbsListView$AdapterDataSetObserver.onChanged(AbsListView.java:6117)
        at android.database.DataSetObservable.notifyChanged(DataSetObservable.java:37)
        at android.widget.BaseAdapter.notifyDataSetChanged(BaseAdapter.java:50)
        at android.support.v4.widget.CursorAdapter.swapCursor(CursorAdapter.java:347)
        at android.support.v4.widget.SimpleCursorAdapter.swapCursor(SimpleCursorAdapter.java:326)
        at android.support.v4.widget.CursorAdapter.changeCursor(CursorAdapter.java:315)
        at android.support.v4.widget.CursorFilter.publishResults(CursorFilter.java:68)
        at android.widget.Filter$ResultsHandler.handleMessage(Filter.java:282)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5221)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

我的建议方法:

  public synchronized Cursor getSuggestions(String[] selectionArgs) {
    String selection = FIELD_title + " like ? ";

    if (selectionArgs != null) {
        if (!selectionArgs[0].isEmpty()) {
            selectionArgs[0].replaceAll("'", "");
            selectionArgs[0] = "%" + selectionArgs[0] + "%";
        } else {
            selection = null;
            selectionArgs = null;
        }
    }

    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
    queryBuilder.setProjectionMap(mAliasMap);
    queryBuilder.setTables(TABLE2_NAME);
    SQLiteDatabase db = mSearchDBOpenHelper.getReadableDatabase();
    Cursor c = null;
    if (db.isOpen()) {
        c = queryBuilder.query(db,
                new String[]{"_ID",
                        SearchManager.SUGGEST_COLUMN_TEXT_1,
                        SearchManager.SUGGEST_COLUMN_TEXT_2,
                        SearchManager.SUGGEST_COLUMN_ICON_1,
                        SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID},
                selection,
                selectionArgs,
                null,
                null,
                FIELD_title + " asc ", "10"
        );
    }
    return c;
}

现在我想说明我的数据库只被实例化一次,我没有泄漏它,我只有一个活动。我注意到的是,当出现竞争条件时,更有可能发生此错误。我的onQueryTextChange监听器:

public boolean onQueryTextChange(String newText) {
            query = newText;
            query = query.replaceAll("[\\s%\"^#<>{}\\\\|`]", "%20");

            if (query.length() > 1) {
            // same problem here
               fireOtherMethod();
            } else {
                    String[] selArgs = {query};
                    searchDB.cleanAutoCompleteRecords();
                    Log.e("c.isClosed()", String.valueOf(searchDB.getSuggestions(selArgs).isClosed()));
                     searchAdapter.changeCursor(searchDB.getSuggestions(selArgs));
            }

            return true;
        }

日志报告光标始终打开,我的数据库也是。当我尝试更改光标时发生错误:

  

searchAdapter.changeCursor(searchDB.getSuggestions(selArgs));

所以,如果我只是开枪:

  

searchDB.getSuggestions(selArgs)

没有问题,没有崩溃。

我无法发现此错误。我不知道我做错了什么。任何帮助将不胜感激!

更新 我试过这样做:

Cursor c = searchDB.getSuggestions(selArgs); 
Cursor oldC = searchAdapter.getCursor(); 
if (oldC != null && !oldC.isClosed()) 
  oldC.close(); 
if (!c.isClosed()) 
  searchAdapter.changeCursor(c); 
else searchAdapter.changeCursor(null);

但结果是一样的。

2 个答案:

答案 0 :(得分:3)

当您调用changeCursor时,您正在关闭现有游标。

  

public void changeCursor(Cursor cursor)

     

在API级别1中添加将基础游标更改为新游标。如果   有一个现有的光标将被关闭。

您可以尝试关闭当前光标然后创建新光标,而不是在尚未创建新光标时将其传递给changeCursor(新光标)。

总是很好检查当前光标是否存在或是否已关闭,如果在尝试时出现这些错误。

https://developer.android.com/reference/android/widget/CursorAdapter.html

答案 1 :(得分:3)

我设法找到了解决方案。似乎问题出在changeCursor方法中:

http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/5.1.0_r1/android/widget/CursorAdapter.java#CursorAdapter.changeCursor%28android.database.Cursor%29

当我使用backspace清除searchView中的文本时,我认为发生了这么多次事件,并且还调用了changeCursor方法。这会关闭旧光标,也许此时旧光标有可能尝试从数据库进行查询。所以我重写了changeCursor方法:

        searchAdapter = new SimpleCursorAdapter(getApplicationContext(), R.layout.suggestionrow, null, from, to, 0) {
        @Override
        public void changeCursor(Cursor cursor) {
            super.swapCursor(cursor);
        }
    };

现在一切都很好。