Search code examples
androidsimplecursoradapterillegalstateexception

Android IllegalStateException on orientation change in getView of SimplecursorAdapter


I get a IllegalStateException when changing orientation. I have a listView using a SimpleCursorAdapter and a ContentProvider. Any ideas what causes this exception?

EDIT

I must've changed something since I only see the exception when selecting an item from the actionbar spinner and then change the orientation. the action bar spinner has three items: Show All, Show Date, Show Location

When the user selects one, it queries the database (see onNavigationItemSelected()). I tried closing the cursor in onStop() but that didn't solve the problem. Where would be the right place to close it?

in MainActivity:

 private  Cursor mCursor = null;

 public void onCreate() {
    mSimpleCursorAdapter = new SpecialAdapter(this, 
            R.layout.row,
            null,
            //cursor,
            PROJECTION,
            new int[] { R.id.titleID, R.id.dateTimeOrLocationID1 , R.id.dateTimeOrLocationID2 },
            CursorAdapter.NO_SELECTION);

    mListView = (ListView) findViewById(android.R.id.list);
    mListView.setAdapter(mSimpleCursorAdapter);


    mOnNavigationListener = new OnNavigationListener() {

          @Override
          public boolean onNavigationItemSelected(int position, long itemId) {

              switch(position) { 
              case 0:
                  mCursor = getContentResolver().query(ReminderContentProvider.CONTENT_URI, PROJECTION, null, null, null);
                  break;
              case 1:

                  mCursor = getContentResolver().query(ReminderContentProvider.CONTENT_URI, PROJECTION, " Date NOT NULL", null, null);
                  break;
              case 2:
                  mCursor = getContentResolver().query(ReminderContentProvider.CONTENT_URI, PROJECTION, " Address NOT NULL", null, null);
                  break;
              default:
                  break;
              }
            getLoaderManager().restartLoader(0, null, MainActivity.this);
            return true;
          }
        };
}

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    CursorLoader loader = new CursorLoader(this, ReminderContentProvider.CONTENT_URI, PROJECTION, null, null, null);
    return loader;
}

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
    mSimpleCursorAdapter.swapCursor(data);
}

@Override
public void onLoaderReset(Loader<Cursor> loader) {
    mSimpleCursorAdapter.swapCursor(null);
}

SimpleCursorAdapter:

@Override
public View getView(int position, View convertView, ViewGroup parent) {

    Cursor mCursor = (Cursor) getItem(position); // exception
    if(mCursor != null)
    {
              ........
    }
 }

EDIT

E/ACRA    ( 3348): com.example.locationreminder fatal error : attempt to re-open an already-closed   object: SQLiteQuery: SELECT _id, Title, Date, Address, Radius, Repetition FROM reminder
E/ACRA    ( 3348): java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteQuery: SELECT _id, Title, Date, Address, Radius, Repetition FROM reminder
E/ACRA    ( 3348):  at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55)
E/ACRA    ( 3348):  at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:58)
E/ACRA    ( 3348):  at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:151)
E/ACRA    ( 3348):  at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:124)
E/ACRA    ( 3348):  at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:213)
E/ACRA    ( 3348):  at android.database.CursorWrapper.moveToPosition(CursorWrapper.java:162)
E/ACRA    ( 3348):  at android.widget.CursorAdapter.getItem(CursorAdapter.java:207)
E/ACRA    ( 3348):  at com.example.locationreminder.SpecialAdapter.getView(SpecialAdapter.java:51)
E/ACRA    ( 3348):  at android.widget.AbsListView.obtainView(AbsListView.java:2271)
E/ACRA    ( 3348):  at android.widget.ListView.makeAndAddView(ListView.java:1769)

Solution

  • I am not sure this is the reason of failure, but there is clearly bug in your code: you try to mix manual cursor management with loader. In OnNavigationItemSelected you call changeCursor. There are several problems:

    1. You load data in UI thread, loaders exist to avoid this
    2. changeCursor closes old cursor. But this cursor is owned by loader, you shouldn't close it, it will be closed by loader after it calls OnLoadFinished
    3. It is not clear where manually created cursors are closed.

    What you should do in OnNavigationItemSelected is to restart loader with new query parameters.