【问题标题】:java.lang.IllegalStateException: attempt to re-open an already-closed objectjava.lang.IllegalStateException:尝试重新打开一个已经关闭的对象
【发布时间】:2011-09-17 15:01:26
【问题描述】:

我试图弄清楚为什么我偶尔会收到 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) {
            // ...
        }
    }
}

【问题讨论】:

  • 请从异常中添加完整的堆栈跟踪。

标签: android multithreading cursor illegalstateexception


【解决方案1】:

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

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

【讨论】:

  • 真的帮了我大忙!谢谢。
【解决方案2】:

听起来您需要同步在 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);
        } 
        }
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多