3

I'm trying to figure out why occasionally I'm getting the IllegalStateException. I can't find any good examples that show how to load a list using a thread to query a SQLite database. I've included my code below. Most of the time it works correctly, but occasionally, I'm getting the IllegalStateException.

I have also gotten a similar exception in another activity of mine that is an instance of ExpandableListActivity. That exception states "trying to requery an already closed cursor".

Can somebody tell me the correct way to do this so that it doesn't cause any errors? I would prefer to use the cursors instead of copying all of the data into memory. If I can't figure this out then I will have to load it all into memory.

I think the issue has something to do with startManagingCursor(Cursor) and the fact that the database connection is closed in onDestroy(). plz help
-- tale

public class MyListActivity extends ListActivity {
    private MyCursorAdapter adapter;
    private SQLiteDatabase db = null;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        try {
            new RetrieveCursorTask(this).execute((Void[]) null);
        } catch (Exception e) {
        }
    }

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

        // Null out the cursor. 
        if (adapter != null) {
            adapter.changeCursor(null);
            adapter = null;
        }

        if (db != null && db.isOpen()) {
            db.close();
        }
    }

    private class RetrieveCursorTask extends AsyncTask<Void, Void, Cursor> {
        private Context ctx;

        public RetrieveCursorTask(Context ctx) {
            this.ctx = ctx;
        }

        @Override
        protected Cursor doInBackground(Void... params) {
            Cursor cursor = null;
            DbHelper helper = new DbHelper(ctx);

            try {
                db = helper.getReadableDatabase();
                cursor = db.query("users",
                    new String[] {
                        DbHelper.ID_COLUMN,
                        DbHelper.UID_COLUMN
                    }, 
                    null, null, null, null, null);
                startManagingCursor(cursor);
            } catch (Exception e) {
            }
            return cursor;
        }

        @Override
        protected void onPostExecute(Cursor cursor) {
            super.onPostExecute(cursor);

            if (cursor != null) {
                try {
                    adapter = new MyCursorAdapter(ctx, cursor);
                } catch (Exception e) {
                }
                setListAdapter(adapter);
            } 
        }
    }

    private class MyCursorAdapter extends CursorAdapter {
        private Context ctx;

        public MyCursorAdapter(Context context, Cursor c) {
            super(context, c);
            this.ctx = context;
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            // ...
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            // ...
        }
    }
}
4

2 回答 2

4

如果您想以您想要的方式查询数据库,请查看AsyncQueryHandler 。

您的任务 RetrieveCursorTask 在单独的线程上运行,因此当您的活动被破坏时,您的 AsyncTask 可能仍在后台运行,但是当您在主活动 onDestroy 中关闭光标时,可能会在您的 AsyncTask 返回后再次重新查询。

于 2011-06-18T06:10:43.393 回答
0

听起来您需要同步在 onPostExecute 中设置适配器的块。问题是由于 AsyncTask 在单独的线程上运行,因此无法保证设置光标和随后请求的顺序。尝试这个..

    @Override
    protected void onPostExecute(Cursor cursor) {
        super.onPostExecute(cursor);

        synchronized(anyObject) {
        if (cursor != null) {
            try {
                adapter = new MyCursorAdapter(ctx, cursor);
            } catch (Exception e) {
            }
            setListAdapter(adapter);
        } 
        }
    }
于 2011-08-12T12:49:42.600 回答