使用SimpleCursorAdapter的Android ListView – 崩溃onResume

我在AcitivityA中有一个ListView ,它使用名为RecipeAdapter的自定义SimpleCursorAdapter RecipeAdapter 。 适配器保存来自SQLite数据

ListView顶部有一个EditText视图,用于在用户搜索配方时过滤listview。 当用户单击筛选的ListView的项目时, ActivityB启动。

一切都很完美。 但是,当用户按下后退按钮以恢复ActivityB ,我收到以下错误。

 java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor@418af170 

我试图解决这个问题:

  • onCreate()中的代码复制到onResume方法。
  • c.requery()添加到onResume()方法
  • db.close添加到onDestroy()方法

任何人都可以帮我解决我的问题吗?

这是我的代码:

onCreatecursor使用c.getCursor填充ListView ,当用户通过EditText过滤ListView ,使用c.getFilterCursor

 public class RecipeActivity extends SherlockListActivity { private DBHelper db = null; private Cursor c = null; private RecipeAdapter adapter = null; ListView listContent; private EditText filterText = null; @SuppressWarnings("deprecation") @Override public void onCreate(Bundle savedInstanceState) { try { super.onCreate(savedInstanceState); setContentView(R.layout.filter_list); filterText = (EditText) findViewById(R.id.search_box); filterText.addTextChangedListener(filterTextWatcher); ListView listContent = getListView(); db = new DBHelper(this); db.createDataBase(); db.openDataBase(); c = db.getCursor(); adapter = new RecipeAdapter(c); listContent.setAdapter(adapter); adapter.setFilterQueryProvider(new FilterQueryProvider() { public Cursor runQuery(CharSequence constraint) { // Search for states whose names begin with the specified letters. c = db.getFilterCursor(constraint); return c; } }); startManagingCursor(c); } catch (IOException e) { e.printStackTrace(); } } private TextWatcher filterTextWatcher = new TextWatcher() { public void afterTextChanged(Editable s) { } public void beforeTextChanged(CharSequence s, int start, int count, int after) { } public void onTextChanged(CharSequence s, int start, int before, int count) { adapter.getFilter().filter(s); } }; 

RecipeAdapter内部类

 class RecipeAdapter extends CursorAdapter { @SuppressWarnings("deprecation") public RecipeAdapter(Cursor c) { super(RecipeActivity.this, c); } public void bindView(View row, Context arg1, Cursor arg2) { RecipeHolder holder = (RecipeHolder) row.getTag(); holder.populateFrom(c, db); } public View newView(Context arg0, Cursor arg1, ViewGroup arg2) { LayoutInflater inflater = getLayoutInflater(); View row = inflater.inflate(R.layout.reciperow, arg2, false); RecipeHolder holder = new RecipeHolder(row); row.setTag(holder); return (row); } static class RecipeHolder { public TextView id = null; private TextView name = null; private TextView desc = null; private TextView preptime = null; private TextView cooktime = null; private TextView serves = null; private TextView calories = null; private TextView fat = null; private TextView fav = null; RecipeHolder(View row) { id = (TextView) row.findViewById(R.id.id); name = (TextView) row.findViewById(R.id.recipe); desc = (TextView) row.findViewById(R.id.desc); preptime = (TextView) row.findViewById(R.id.preptime); cooktime = (TextView) row.findViewById(R.id.cooktime); serves = (TextView) row.findViewById(R.id.serving); calories = (TextView) row.findViewById(R.id.calories); fat = (TextView) row.findViewById(R.id.fat); fav = (TextView) row.findViewById(R.id.fav); } void populateFrom(Cursor c, DBHelper r) { id.setText(r.getId(c)); name.setText(r.getRecipe(c)); name.setTextColor(Color.parseColor("#CCf27c22")); desc.setText(r.getDesc(c)); preptime.setText(r.getPrepTime(c) + ". "); cooktime.setText(r.getCookTime(c) + " mins"); serves.setText(r.getServes(c)); calories.setText(r.getCalories(c)); fat.setText(r.getFat(c)); fav.setText(r.getFav(c)); 

来自DBHelper类的getCursor()和getFilterCursor()代码

 public Cursor getCursor() { SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); queryBuilder.setTables(DATABASE_TABLE); String[] columns = new String[] { KEY_ROWID, RECIPE, DESC, PREPTIME, COOKTIME, SERVES, CALORIES, FAT, CATEGORY, FAV }; Cursor myCursor = queryBuilder.query(myDataBase, columns, null, null, null, null, RECIPE + " ASC"); return myCursor; } public Cursor getFilterCursor(CharSequence constraint) { SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); queryBuilder.setTables(DATABASE_TABLE); String[] columns = new String[] { KEY_ROWID, RECIPE, DESC, PREPTIME, COOKTIME, SERVES, CALORIES, FAT, CATEGORY, FAV }; if (constraint == null || constraint.length() == 0) { // Return the full list return queryBuilder.query(myDataBase, columns, null, null, null, null, RECIPE + " ASC"); } else { String value = "%" + constraint.toString() + "%"; return myDataBase.query(DATABASE_TABLE, columns, "RECIPE like ? ", new String[] { value }, null, null, null); } } 

完整的LOGCAT

 FATAL EXCEPTION: main java.lang.RuntimeException: Unable to resume activity {ttj.android.quorn/ttj.android.quorn.RecipeActivity}: java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor@41954658 at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2456) at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2484) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1185) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4507) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:511) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor@41954658 at android.app.Activity.performRestart(Activity.java:4508) at android.app.Activity.performResume(Activity.java:4531) at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2446) 

您运行应用程序的Android平台版本是不是? 从Honeycomb开始,不推荐使用此方法startManagingCursor。 建议开发人员使用新的CursorLoader类和LoaderManager,也可以通过Android兼容包在旧版平台上使用。

实际上我在Honeycomb上遇到了同样的问题。 但是我没有遵循上面的说明,因为我没有太多时间来重写我的代码。 所以这是我的解决方案,我希望它有所帮助。 但是如果你有时间,你应该切换到使用CursorLoader和LoaderManager,它可以获得更好的性能。

 @Override protected void onResume() { super.onResume(); //do the query again every time on resume Cursor c = mExpenseDb.queryCategories(mSettings.getCurrentAccount().getId()); //mAdapter is a SimpleCursorAdapter, set its cursor to the new one mAdapter.changeCursor(c); } @Override protected void onPause() { super.onPause(); //mAdapter is a SimpleCursorAdapter, invalidate its data and set it cursor to null on Activity pause mAdapter.notifyDataSetInvalidated(); mAdapter.changeCursor(null); }