StaleDataException with dialog
Asked Answered
G

3

7

I am trying to show a dialog with a listview with names from my database but I keep getting a StaleDataException. I know that usually means I am trying to use data from a closed cursor but the cursor does not close until I get all the data so I dont understand why I am getting this

d = new Dialog(this);
d.setContentView(R.layout.dialog_layout);
d.setTitle("Select Bowler");

ListView lv = (ListView)d.findViewById(R.id.dialog_list);
Cursor c = getContentResolver().query(
    BowlersDB.CONTENT_URI,
    new String[] {
        BowlersDB.ID, BowlersDB.FIRST_NAME, BowlersDB.LAST_NAME
    },
    null,
    null,
    BowlersDB.LAST_NAME + " COLLATE LOCALIZED ASC"
);

if (c.moveToFirst() && c != null) {
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(
        this,
        R.layout.names_listview,
        c,
        new String[] {
            BowlersDB.FIRST_NAME, BowlersDB.LAST_NAME
        },
        new int[] {
            R.id.bListTextView, R.id.bListTextView2
        },
        0
    );
    lv.setAdapter(adapter);
    lv.setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> arg0, View v, int position, long id) {
            bowlerClickedID = id;
            updateName(id);
        }
    });
    d.show();
}
c.close();

error

android.database.StaleDataException: 
   Attempting to access a closed CursorWindow. 
   Most probable cause: cursor is deactivated prior to calling this method.

   at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:139)
   at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
   at android.database.CursorWrapper.getString(CursorWrapper.java:114)
   at android.widget.SimpleCursorAdapter.bindView(SimpleCursorAdapter.java:150)
   at android.widget.CursorAdapter.getView(CursorAdapter.java:250)
   at android.widget.AbsListView.obtainView(AbsListView.java:2267)
   at android.widget.ListView.measureHeightOfChildren(ListView.java:1244)
   at android.widget.ListView.onMeasure(ListView.java:1156)
   at android.view.View.measure(View.java:15172)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4814)
   at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1390)
   at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
   at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
   at android.view.View.measure(View.java:15172)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4814)
   at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
   at android.view.View.measure(View.java:15172)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4814)
   at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
   at android.view.View.measure(View.java:15172)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4814)
   at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1390)
   at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
   at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
   at android.view.View.measure(View.java:15172)
   at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:4814)
   at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
   at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2148)
   at android.view.View.measure(View.java:15172)
   ...

EDIT: If I comment out the c.close() line it works fine but I cant just leave the cursor open though so what do I do?

Gillett answered 29/9, 2012 at 17:14 Comment(0)
E
4

You cannot close the cursor until CursorAdapter is no longer needed. So you can close it in onDestroy() method:

@Override
public void onDestroy() {
 super.onDestroy();

 ListView lv = (ListView) d.findViewById(R.id.dialog_list);
 ((CursorAdapter) lv.getAdapter()).getCursor().close();
 database.close();
}
Effloresce answered 2/10, 2012 at 16:44 Comment(0)
P
9

You're getting your error because you're closing the Cursor while the SimpleCursorAdapter you create might still be trying to access data from it.

If you want to use a CursorLoader, as you should be doing.

  1. Keep a reference to your adapter as an instance variable
  2. Create your simple cursor adapter with a reference to null for the cursor
  3. Have your class implement LoaderManager.LoaderCallbacks<Cursor>
  4. Actually create the CursorLoader in the onCreateLoader
  5. In onLoadFinished(), swap the cursors with adapter.swapCursor(cursor)
  6. In onLoaderReset(), swap the cursor with a null cursor as adapter.swapCursor(null)`

You should also end up putting your data in a ContentProvider - it's not that bad!

Poor answered 9/10, 2012 at 9:34 Comment(1)
Why swapCursor ( developer.android.com/reference/android/support/v4/widget/… ) rather than changeCursor ( developer.android.com/reference/android/support/v4/widget/… ) ?Width
E
4

You cannot close the cursor until CursorAdapter is no longer needed. So you can close it in onDestroy() method:

@Override
public void onDestroy() {
 super.onDestroy();

 ListView lv = (ListView) d.findViewById(R.id.dialog_list);
 ((CursorAdapter) lv.getAdapter()).getCursor().close();
 database.close();
}
Effloresce answered 2/10, 2012 at 16:44 Comment(0)
O
0

I used to rely on startManagingCursor method to leave the hassle of opening and closing Cursors to the system. Now that it is deprecated (it still works but I would not recommend using it), consider using the CursorLoader class with LoaderManager and leave it to the system to handle the Cursor closing.

Orpha answered 3/10, 2012 at 8:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.