Finalizing a Cursor that has not been deactivated

2019-01-16 10:41发布

问题:

i'm getting a "Finalizing a Cursor that has not been deactivated or closed" error on this piece of code. The code is used to fill a listview.

Since it's a non-fatal error , there is no crash and all seems to works fine..but i don't like the error.

If i close the cursor at the end of this code..the listview stay's empty. if i close the cursor in onStop , i get the same error.

How do i fix this??

private void updateList() { 
        DBAdapter db = new DBAdapter(this); 
        db.open(); 
            //load all waiting alarm 
            mCursor=db.getTitles("state<2"); 
            setListAdapter(new MyCursorAdapter(this, mCursor)); 
            registerForContextMenu(getListView()); 
            db.close(); 
        } 


error : 


E/Cursor  ( 2318): Finalizing a Cursor that has not been deactivated 
or closed. database = /data/data/xxxxxxxxxxxxxxx.db, table = alerts, 
query = SELECT _id, alert_id, 
E/Cursor  ( 2318): 
android.database.sqlite.DatabaseObjectNotClosedException: Application 
did not close the cursor or database 
object that was opened here 
E/Cursor  ( 2318):      at 
android.database.sqlite.SQLiteCursor.<init>(SQLiteCursor.java:210) 
E/Cursor  ( 2318):      at 
android.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDr­iver.java: 
53) 
E/Cursor  ( 2318):      at 
android.database.sqlite.SQLiteDatabase.rawQueryWithFactory(SQLiteDatabase.j­ava: 
1345) 
E/Cursor  ( 2318):      at 
android.database.sqlite.SQLiteDatabase.queryWithFactory(SQLiteDatabase.java­: 
1229) 
.... 
.... 

回答1:

You should not be getting that message if you close the Cursor in onStop() or onDestroy(). Please try that again. Or, call startManagingCursor() after you get the Cursor from your query, and Android will close the Cursor on its own.



回答2:

Scott,

I ran into the same problem as you. Before you close your database, i.e. "db.close()," make sure that your cursors are closed first, i.e. "mCursor.close()"

Like so:

private void updateList()
{ 
    DBAdapter db = new DBAdapter(this);
    db.open();

    //load all waiting alarm
    mCursor=db.getTitles("state<2"); 
    setListAdapter(new MyCursorAdapter(this, mCursor)); 
    registerForContextMenu(getListView()); 

    // Let's close the cursor.
    mCursor.close();
    db.close(); 
} 

You mentioned that if you closed your cursor your list view stays empty. I recommend you pass the information over to a class and copy it over (allocate the memory) then close the cursor.



回答3:

When a query returns a cursor it is actually positioned "before" the first record in the cursor. An adapter will attempt do a 'getItem' at the first element so it will fail as the cursor is not positioned at any.

In my base adapters I do a cursorMoveToPosition on the getViews. This seems to eliminate the need for the movefirst.



回答4:

Do not use startManagingCursor() since that is no longer the recommended approach. The issue occurs because a cursor / DB connection is still not closed by the time the finalizer gets to this object. You can avoid that by either allowing a loader to manage the cursor or by tracking all cursor / DB / SQLiteOpenHelper connections yourself and cleaning up after them.

Using a Loader is fairly cumbersome and requires a lot of moving parts for it to work in conjunction with say a list view. On the other hand tracking your cursor and database connections is prone to human error. If the number of cursor / DB objects is low, I'd recommend the latter solution. If not, let a loader handle your connections.



回答5:

Close the cursor object wherever you are creating it.

When you create a cursor object and done with traversing through a SQLite table then close it after it has been used. This closing of cursor prevents exception in logcat.

You will not get any exception related to finalizing the cursor that left opened.

This fixed same issue in my Application.



回答6:

I struggled with this problem for two days. I was trying to get sample code working which passed a cursor, returned from a database query, directly to List Adapter - no interim adapter. It refused to work - just displayed a blank screen - until I invoked 'moveToFirst()' on the cursor before passing it to the ListAdapter. Go figure! When I comment this out, it breaks.

Just thought that I'd share this to save people the same struggles that I had.

If anyone can shed some light on why this is so, I'd appreciate it. I haven't had to invoke moveToFirst on cursors up to now, to get them to perform properly.



回答7:

Just had the same problem and thought to let you know - just in case....

I accidentally called my fetch routine two times and hereby "lost" the resulting cursor of the first call. This caused the error.



回答8:

I too have been having issues with the closing the cursor:

  • Closing the cursor right after setting the list view's adapter causes the cursor to close before the data gets displayed.

  • Can't use startManagingCursor to manage the cursor because it has been deprecated.

  • The new cursorLoader replacement for startManagingCursor seems to be overkill.

  • Moving the cursor's position as suggested did not work.

  • Making the task an inner class of the activity and closing the cursor in the activity's onDestroy method works sometimes but not all the time.

  • Making the task an inner class of the activity and closing the cursor in the activity's onStop method seems to be working.

I also found out that I can close the database and the sqlite open helper before closing the cursor. I can even close them right after setting the list view's adapter. The data will still display.



回答9:

startManagingCursor(cursor);

This has fixed my problem