Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IllegalStateException: database already closed (using ViewPager)

I'm stumped as to what is causing this error, as I have made sure that I am closing my database adapter properly (at least I think I am). Here's what LogCat's saying (the tag for all of them is AndroidRuntime):

FATAL EXCEPTION: main java.lang.IllegalStateException: database /data/data/com.acedit.assignamo/databases/data.db (conn# 0) already closed at android.database.sqlite.SQLiteDatabase.verifyDbIsOpen(SQLiteDatabase.java:2082) at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:413) at android.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:400) at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:79) at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:164) at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:147) at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:178) at android.support.v4.widget.CursorAdapter.getItemId(CursorAdapter.java:225) at android.widget.AbsListView.onSaveInstanceState(AbsListView.java:1569) at android.view.View.dispatchSaveInstanceState(View.java:9868) at android.view.ViewGroup.dispatchFreezeSelfOnly(ViewGroup.java:2310) at android.widget.AdapterView.dispatchSaveInstanceState(AdapterView.java:770) at android.view.ViewGroup.dispatchSaveInstanceState(ViewGroup.java:2296) at android.view.View.saveHierarchyState(View.java:9851) at android.support.v4.app.FragmentManagerImpl.saveFragmentViewState(FragmentManager.java:1561) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:962) at android.support.v4.app.FragmentManagerImpl.detachFragment(FragmentManager.java:1233) at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:620) at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1431) at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:431) at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141) at android.support.v4.view.ViewPager.populate(ViewPager.java:895) at android.support.v4.view.ViewPager.populate(ViewPager.java:772) at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:1539) at android.support.v4.view.ViewPager.computeScroll(ViewPager.java:1422) at android.view.View.getDisplayList(View.java:10406) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597) at android.view.View.getDisplayList(View.java:10380) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597) at android.view.View.getDisplayList(View.java:10380) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597) at android.view.View.getDisplayList(View.java:10380) at android.view.ViewGroup.dispatchGetDisplayList(ViewGroup.java:2597) at android.view.View.getDisplayList(View.java:10380) at android.view.HardwareRenderer$GlRenderer.draw(HardwareRenderer.java:875) at android.view.ViewRootImpl.draw(ViewRootImpl.java:1910) at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1634) at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2442) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:4575) 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:786) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method)

My code:

public Cursor fetchIncompleteAssignments(Short course) {
    DbAdapter adapter = new DbAdapter(context, null, Values.ASSIGNMENT_TABLE);
    adapter.open();

    Cursor r;
    if (course == null) // Fetching from all courses
        r = adapter.fetchAllWhere(Values.ASSIGNMENT_LIST_FETCH, Values.ASSIGNMENT_KEY_STATUS + "=" + 0, Values.ASSIGNMENT_KEY_DUE_DATE);
    else
        r = adapter.fetchAllWhere(Values.ASSIGNMENT_LIST_FETCH, Values.ASSIGNMENT_KEY_COURSE + "=" + course
            + " AND " + Values.ASSIGNMENT_KEY_STATUS + "=" + 0, Values.ASSIGNMENT_KEY_DUE_DATE);
    adapter.close();
    return r;
}

// Part of DbAdapter:
public DbAdapter open() throws SQLException {
    dbHelper = new DatabaseHelper(context);
    db = dbHelper.getWritableDatabase();
    return this;
}

public void close() {
    if (db != null) {
        try {
            db.close();
            dbHelper.close();
        } catch (NullPointerException e) {
            Log.e("Close", "Error: " + e + " " + e.getMessage());
        }
    } else
        Log.e("Close", "Error! db \"" + DATABASE_TABLE + "\" is null.");
}

The Cursor returned from fetchAllAssignments() is used to populate a ListView through a custom CursorAdapter. The ListView is the content of a ListFragment, and there are multiple instances of this ListFragment displayed in each page of a ViewPager (one for showing assignments from all courses, and then a page for each of the individual courses).

Any ideas as to what is wrong? As far as I know, I'm closing my database correctly. Let me know if you need more code. Thanks in advance!

EDIT: The data is pulled from the database fine, and it populates the ListView as well. I can swipe through the various pages, but it seems to crash whenever the Fragment is stopped. It will often crash when I start another Activity, but not always. It will also occasionally crash when I'm swiping through the pages, though very rarely. Here's my onPause() method for my Fragment (I don't have an onStop() or onDestroy()):

public void onPause() {
    super.onPause();
    if (!assignmentsCursor.isClosed()) {
        assignmentsCursor.close();
        assignmentsCursor = null;
    }
}

In my onResume() I just reload the list from the database and get a new copy of the context via getActivity(). Perhaps something is getting cleared (for memory purposes) and I'm not reloading it? I'm not getting any kind of NullPointerException, so this seems unlikely to me...

like image 428
mightimaus Avatar asked Oct 03 '12 05:10

mightimaus


2 Answers

this exception actually is raised because you double close your database, not because you did not close it.

so..

in you close() method, replace the following line in your code:

if (db != null) {

with:

if (db != null && db.isOpen()) {
like image 184
kdehairy Avatar answered Nov 07 '22 13:11

kdehairy


Make your DbHelper a singleton, as described in this post.

like image 2
Alex Lockwood Avatar answered Nov 07 '22 11:11

Alex Lockwood