问题
I'm totally new to android programming. I can see that this problem has been raised many times before. However, I am still not able to see what the problem is. I'm trying to connect the data from an SQLite database to a listview. In the ListActivity my onCreate looks like the following:
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);
}
It raises the following exception, which I hope somebody 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
回答1:
Do not close your cursor in your onCreate
method. It is referenced by your adapter, but it is not already used !
Try using a LoaderManager / CursorLoader. It is the new way for handling cursors : How to transition from managedQuery to LoaderManager/CursorLoader?
Here is an example from one of my projects (I did not test 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 of the SimpleCursorLoader : https://gist.github.com/1217628 (via https://stackoverflow.com/a/7422343/615882 )
回答2:
Your SimpleCursorAdapter is tied to your Cursor, it's 'supplying' your adapter with the data fromt the Cursor. Think of your adapter as just that, an adapter, it lies on top of your Cursor and handles the delegation of data from your Cursor to your ListView. So, you should only close your Cursor when you aren't using your ListView anymore, fx. in onPause()
(when the Activity isn't shown to the user anymore).
回答3:
I think the cursor
continues to be used by the adapter
, so you probably shouldn't close it right there.
You could use Activity.startManagingCursor()
which will have the Activity
take care of closing it for you when it's no longer used.
来源:https://stackoverflow.com/questions/12358864/illegalstateexception-attempt-to-re-open-an-already-closed-object-simplecursor