java.lang.IllegalStateException: попытка повторно открыть уже закрытый объект

Я пытаюсь понять, почему иногда я получаю исключение IllegalStateException. Я не могу найти хороших примеров, показывающих, как загружать список с помощью потока для запроса базы данных SQLite. Я включил свой код ниже. В большинстве случаев он работает правильно, но иногда я получаю исключение IllegalStateException.

Я также получил подобное исключение в другом моем действии, которое является экземпляром ExpandableListActivity. В этом исключении указано «попытка запросить уже закрытый курсор».

Может ли кто-нибудь сказать мне правильный способ сделать это, чтобы это не вызывало никаких ошибок? Я бы предпочел использовать курсоры вместо копирования всех данных в память. Если я не могу понять это, мне придется загрузить все это в память.

Я думаю, что проблема как-то связана с startManagingCursor(Cursor) и тем фактом, что соединение с базой данных закрывается в onDestroy(). помогите плиз
-- сказка

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) {
            // ...
        }
    }
}

person TALE    schedule 18.06.2011    source источник
comment
пожалуйста, добавьте полную трассировку стека из исключения.   -  person Nick Campion    schedule 18.06.2011


Ответы (2)


Посмотрите AsyncQueryHandler, если вы хотите запрашивать БД так, как хотите.

Ваша задача RetrieveCursorTask выполняется в отдельном потоке, поэтому, когда ваша активность будет уничтожена, ваша AsyncTask может по-прежнему работать в фоновом режиме, но, поскольку вы закрыли свой курсор в основной активности onDestroy, он может быть повторно запрошен после возврата вашей AsyncTask.

person mkso    schedule 18.06.2011
comment
Реально выручил меня! Спасибо. - person Gio; 14.09.2012

Похоже, вам нужно синхронизировать блок, в котором вы установили свой адаптер в 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);
        } 
        }
    }
person brockoli    schedule 12.08.2011