Java.lang.IllegalStateException: Attempting to reopen an already closed object: SQLiteQuery

So, I have this strange error. I am using a simple cursor adapter for my searchView and database suggestion. I don't need a content provider, so I don't use one. The thing is, I don't have a command that closes my DB or cursor anywhere in my code, but I still get this error. Mistake:

    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)

      

My suggestion method:

  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;
}

      

Now I would like to point out that my DB is only created once, I am not leaking it and I only have one action. I noticed that this error is most likely to happen when there is a race condition. My onQueryTextChange listener:

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;
        }

      

The log says the cursor is always open, my db also. Error when trying to change cursor:

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

So, if I just shoot:

searchDB.getSuggestions (selArgs)

No problem, no glitches.

I cannot catch this error. I have no idea what I am doing wrong. Any help would be appreciated!

Update: I've tried doing this:

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);

      

But the result is the same.

+3


source to share


2 answers


I managed to find a solution. It seems the problem was with the changeCursor method:

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

What I think happens when I clear the text from the searchView using the backspace, the event is called so many times and also changes the cursor method. This closes the old cursor, and it is possible that the old cursor is currently trying to make a query from the database. Therefore, I override the changeCursor method:



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

      

And now everything is fine.

+2


source


When you call changeCursor, you close the existing cursor.

public void changeCursor (cursor)

Added in API Level 1 Change the base cursor to a new cursor. If there is an existing cursor, it will be closed.

You can try to close the current cursor and then create a new cursor, rather than passing the new cursor through changeCursor (new cursor) if not already created.



It's always a good idea to check if the current cursor exists or is closed if these errors show up when trying to do this.

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

+2


source







All Articles