IllegalStateException: attempt to re-open an already-closed object. SimpleCursorAdapter problems

孤者浪人 提交于 2019-12-20 02:49:11

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!