I have a ListView
in AcitivityA
that is populated using a custom SimpleCursorAdapter
called RecipeAdapter
. The adapter holds data from SQLite
There is a EditText
view at the top of the ListView
, that filters the listview as the user searches for a recipe. When a user clicks on a item in the filtered ListView
, ActivityB
starts.
This all works perfectly. However when the user presses the backbutton to resume ActivityB
, I get the following error.
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@418ae5d8
To fix this problem, I modified the onResume()
from:
... c = db.getCursor(); adapter.changeCursor(c);
to
.... Cursor cursor = db.getCursor(); adapter.changeCursor(cursor);
I then get the following exception. In the Logcat, the problem arises with the getId()
method in DBHelper
. I have added c.moveToFirst()
in this method, but this still doesn't solve the problem.
FATAL EXCEPTION: main android.database.CursorIndexOutOfBoundsException: Index -1 requested, with a size of 70 at android.database.AbstractCursor.checkPosition(AbstractCursor.java:400) at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136) at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50) at ttj.android.quorn.DBHelper.getId(DBHelper.java:224) at ttj.android.quorn.RecipeActivity$RecipeHolder.populateFrom(RecipeActivity.java:650) at ttj.android.quorn.RecipeActivity$RecipeAdapter.bindView(RecipeActivity.java:572) at android.support.v4.widget.CursorAdapter.getView(CursorAdapter.java:256) at android.widget.AbsListView.obtainView(AbsListView.java:2214) at android.widget.ListView.makeAndAddView(ListView.java:1774) at android.widget.ListView.fillDown(ListView.java:672) at android.widget.ListView.fillFromTop(ListView.java:732) at android.widget.ListView.layoutChildren(ListView.java:1611) at android.widget.AbsListView.onLayout(AbsListView.java:2044) at android.view.View.layout(View.java:11418) at android.view.ViewGroup.layout(ViewGroup.java:4224) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486) at android.widget.LinearLayout.onLayout(LinearLayout.java:1399) at android.view.View.layout(View.java:11418) at android.view.ViewGroup.layout(ViewGroup.java:4224) at android.widget.FrameLayout.onLayout(FrameLayout.java:431) at android.view.View.layout(View.java:11418) at android.view.ViewGroup.layout(ViewGroup.java:4224) at android.widget.LinearLayout.setChildFrame(LinearLayout.java:1628) at android.widget.LinearLayout.layoutVertical(LinearLayout.java:1486) at android.widget.LinearLayout.onLayout(LinearLayout.java:1399) at android.view.View.layout(View.java:11418) at android.view.ViewGroup.layout(ViewGroup.java:4224) at android.widget.FrameLayout.onLayout(FrameLayout.java:431) at android.view.View.layout(View.java:11418) at android.view.ViewGroup.layout(ViewGroup.java:4224) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1628) at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2585) 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)
Can anyone help me with my problem?
Here is my code:
In the onCreate
, the cursor
populate the ListView
using c.getCursor
and when the user filters the ListView
via the EditText
, the c.getFilterCursor
is used.
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(); } } @Override protected void onDestroy() { super.onDestroy(); filterText.removeTextChangedListener(filterTextWatcher); db.close(); } @SuppressWarnings("deprecation") @Override protected void onResume() { super.onResume(); Cursor cursor = db.getCursor(); adapter.changeCursor(cursor); } @Override protected void onPause() { super.onPause(); adapter.notifyDataSetInvalidated(); adapter.changeCursor(null); } 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
inner class
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 class
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); } } public String getId(Cursor c) { c.moveToFirst(); return (c.getString(0)); } public String getRecipe(Cursor c) { return (c.getString(1)); } public String getDesc(Cursor c) { return (c.getString(2)); } public String getPrepTime(Cursor c) { return (c.getString(3)); } public String getCookTime(Cursor c) { return (c.getString(4)); } public String getServes(Cursor c) { return (c.getString(5)); } public String getCalories(Cursor c) { return (c.getString(6)); } public String getFat(Cursor c) { return (c.getString(7)); } public String getCategory(Cursor c) { return (c.getString(8)); } public String getFav(Cursor c) { return (c.getString(9)); }