IllegalStateException: attempt to reopen an already closed object. Problems with SimpleCursorAdapter

I am completely new to Android programming. I see that this problem has been raised many times before. However, I still cannot understand what the problem is. I am trying to connect data from a SQLite database to a list. In ListActivity, my onCreate looks like this:

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_init_key); getActionBar().setDisplayHomeAsUpEnabled(true); DBHandler db = new DBHandler(this); Cursor cursor = db.getKeyPointCursor(1, "Crataegus"); // the desired columns to be bound String[] columns = new String[] { "question1","answer1" }; // the XML defined views which the data will be bound to int[] to = new int[] { R.id.question, R.id.answer }; SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this, R.layout.key_list_entry, cursor, columns, to, 0); cursor.close(); this.setListAdapter(mAdapter); } 

This raises the following exception, which I hope someone can help me with.

 09-10 21:52:01.505: W/dalvikvm(10976): threadid=1: thread exiting with uncaught exception (group=0x40c8e1f8) 09-10 21:52:01.510: E/AndroidRuntime(10976): FATAL EXCEPTION: main 09-10 21:52:01.510: E/AndroidRuntime(10976): java.lang.RuntimeException: Unable to start activity ComponentInfo{jem.danskflora/jem.danskflora.InitKeyActivity}: java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT * FROM Crataegus WHERE _id=?) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1970) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1995) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.ActivityThread.access$600(ActivityThread.java:128) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1161) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.os.Handler.dispatchMessage(Handler.java:99) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.os.Looper.loop(Looper.java:137) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.ActivityThread.main(ActivityThread.java:4514) 09-10 21:52:01.510: E/AndroidRuntime(10976): at java.lang.reflect.Method.invokeNative(Native Method) 09-10 21:52:01.510: E/AndroidRuntime(10976): at java.lang.reflect.Method.invoke(Method.java:511) 09-10 21:52:01.510: E/AndroidRuntime(10976): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:993) 09-10 21:52:01.510: E/AndroidRuntime(10976): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:760) 09-10 21:52:01.510: E/AndroidRuntime(10976): at dalvik.system.NativeStart.main(Native Method) 09-10 21:52:01.510: E/AndroidRuntime(10976): Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT * FROM Crataegus WHERE _id=?) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:33) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:82) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:156) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.widget.CursorAdapter.getCount(CursorAdapter.java:196) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.widget.ListView.setAdapter(ListView.java:467) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.ListActivity.setListAdapter(ListActivity.java:265) 09-10 21:52:01.510: E/AndroidRuntime(10976): at jem.danskflora.InitKeyActivity.onCreate(InitKeyActivity.java:30) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.Activity.performCreate(Activity.java:4562) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1053) 09-10 21:52:01.510: E/AndroidRuntime(10976): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1934) 09-10 21:52:01.510: E/AndroidRuntime(10976): ... 11 more 
+3
source share
3 answers

Do not close the cursor in the onCreate method. It refers to your adapter, but it is not used yet!

Try using LoaderManager / CursorLoader. This is a new way to handle cursors: How do I switch from managedQuery to LoaderManager / CursorLoader?

Here is an example from one of my projects (I have not tested this code):

 public class AdditionalActivitiesListFragment extends ListActivity implements LoaderManager.LoaderCallbacks<Cursor>, OnItemClickListener, OnClickListener { private SimpleCursorAdapter adapter; public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); String[] columns = new String[] { "your", "db", "columns" }; int[] to = new int[] { R.id.your, R.id.fields, R.id.toMapWith }; getLoaderManager().initLoader(0x02, null, this); adapter = new SimpleCursorAdapter(activity.getApplicationContext(), R.layout.row_layout, null, columns, to, SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER); setListAdapter(adapter); } public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { return new SimpleCursorLoader(this) { @Override public Cursor loadInBackground() { Cursor c = // Your cursor return c; } }; } public void onLoadFinished(Loader<Cursor> arg0, Cursor cursor) { adapter.swapCursor(cursor); } public void onLoaderReset(Loader<Cursor> arg0) { adapter.swapCursor(null); } } 

Source SimpleCursorLoader: https://gist.github.com/1217628 (via fooobar.com/questions/54587 / ... )

+4
source

Your SimpleCursorAdapter is attached to your cursor; it "supplies" your adapter with data from the cursor. Think of your adapter in this way, the adapter, it lies on top of your cursor and handles the delegation of data from your cursor to the ListView. Therefore, you must close your Cursor when you are no longer using your ListView, fx. in onPause() (when activity is no longer displayed to the user).

+1
source

I think that cursor continues to be used by adapter , so you probably shouldn't close it there.

You can use Activity.startManagingCursor() , which the Activity will have, to close it for you when it is no longer in use.

0
source

All Articles