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.
source to share
I managed to find a solution. It seems the problem was with the changeCursor method:
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.
source to share
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
source to share