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) {
// ...
}
}
}
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) {
// ...
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您想按照自己想要的方式查询数据库,请查看 AsyncQueryHandler 。
您的任务 RetrieveCursorTask 在单独的线程上运行,因此当您的活动被销毁时,您的 AsyncTask 可能仍在后台运行,但当您在主活动 onDestroy 中关闭光标时,在 AsyncTask 返回后可能会再次重新查询。
Look into AsyncQueryHandler if you want to query DB the way you want.
Your task RetrieveCursorTask is running on separate thread so when your activity gets destroyed your AsyncTask might still be running in background but as you have closed your cursor in main activity onDestroy it might be requeried again after your AsyncTask returns.
听起来您需要同步在 onPostExecute 中设置适配器的块。问题是由于 AsyncTask 在单独的线程上运行,因此无法保证设置游标和随后请求游标的顺序。试试这个..
Sounds like you need to syncronize the block where you set your adapter in onPostExecute. The problem is since AsyncTask is running on a separate thread, the order in which the cursor is set and subsequently requested isn't guaranteed. Try this..