1

On my app i am receiving reports of sporadic cursor errors that only come up on Motorola phones. I am using a ListView backed by a SQLite query to view a directory, and the query is refreshed when the directory is updated remotely or locally.

The most frequent errors we see are:

  • java.lang.IllegalStateException: this should only be called when the cursor is valid
  • java.lang.IllegalStateException: Cursor is closed
  • android.database.StaleDataException: Access closed cursor
  • java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.CursorWindow

Is this a known problem, and is there a fix or a workaround?

I use AsyncTask to update the list:

private class RefreshTask extends AsyncTask<Void, Void, Cursor> {
    protected Cursor doInBackground(Void... params) {
        return ReaderHelper.getItemCursor(getActivity(), ReaderHelper.itemFilter);
    }           

    protected void onPostExecute(Cursor csr) {
        int count = csr.getCount();
        loadingBar.setVisibility(View.GONE);
        if (count == 0) {
            if (ReaderHelper.itemFilter.unread) emptyMessage.setText(getText(R.string.msg_no_item_unread));
            else emptyMessage.setText(getText(R.string.msg_no_item));
        }

        mCursor = csr;
        getActivity().startManagingCursor(mCursor);
        mAdapter.changeCursor(mCursor);

    }   
}   

This is the adapter.

private class ItemsAdapter extends ResourceCursorAdapter {
    private ItemsAdapter(Context c, Cursor csr) {
        super(c, R.layout.item_list_row, csr, false);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view = super.newView(context, cursor, parent);
        view.setTag(new ItemViewHolder());
        return view;
    }

    @Override
    public void bindView(View v, Context c, Cursor csr) {
        ...
    }
}
user579619
  • 165
  • 1
  • 2
  • 7

1 Answers1

0

There still isn't enough code to allow readers to understand what you're doing -- in particular, you don't show how RefreshTask is created. But I notice that RefreshTask is referencing an Activity, presumably the Activity that created it. This could cause problems if the Activity is destroyed while RefreshTask is executing.

Instead of updating the Activity directly, perhaps you should override the Application class, and put the refreshed state there. (See this answer for an example; this answer has another example, and also shows updates needed to your application's manifest.)

Note that if you go this route, you shouldn't have the Activity manage the cursor. Instead, in onPostExecute, you could dump the cursor data into an array that is stored in the Application object.

Community
  • 1
  • 1
Dan Breslau
  • 11,472
  • 2
  • 35
  • 44
  • Thanks for your hint. What should I use instead of getActivity()? Is getActivity().getApplicationContext() ok? – user579619 Jun 28 '11 at 22:37
  • @user579619: It would really help if you'd show the constructor for the RefreshTask class. But to try to answer your question: Don't call `getActivity()`, or do anything with the Activity, from **inside** the RefreshTask. Instead, pass the Application into RefreshTask as a parameter in the constructor. – Dan Breslau Jun 29 '11 at 20:19
  • there is no constructor for the RefreshTask. I just call new RefreshTask().execute. It works on all devices but motorola devices. This error always appears when the CursorApdapter start getView(): java.lang.IllegalStateException: this should only be called when the cursor is valid – user579619 Jun 30 '11 at 23:02
  • @user579619: Code. Need more code. And a stack trace would be helpful too. – Dan Breslau Jul 01 '11 at 11:00
  • I found the problem, I create a WrapperCursor in bindView and it does not close automatically on Motorola devices. Thanks for your help – user579619 Jul 27 '11 at 07:29