19

I have a listview. I get data from an SQLite database. I get this error:

error

It occurs when I go from line 20 to 21:

occur

I placed cursor.deactivate() and cursor.close() on line 50, with no result. Why I get this error and how to solve it?

user4157124
  • 2,809
  • 13
  • 27
  • 42
Timon Devos
  • 443
  • 1
  • 6
  • 18
  • 1
    duplicate of http://stackoverflow.com/questions/3068320/finalizing-a-cursor-that-has-not-been-deactivated-or-closed-non-fatal-error – kosa May 03 '12 at 15:21
  • Unrelated to the answer.. You should call getReadableDatabase() instead of getWriteableDatabase(). No need to get a writeable db object when all you're doing is reading from it. – dymmeh May 03 '12 at 15:36
  • @thinksteep I saw that question but when I tried the solution it didn't work. Thanks for helping – Timon Devos May 04 '12 at 07:56

4 Answers4

25

You have to close the cursor before the database. Put your code in a try / catch block and in a finally block, close the cursor and then close the database:

try {
    db = ...
} catch(Exception ex) { 
    // Log the exception's message or whatever you like
} finally {
    try {
      if( cursor != null && !cursor.isClosed())
        cursor.close();
       if( db.isOpen() )
        db.close();
    } catch(Exception ex) {}
}

Closing sequence matters a lot while doing IO with DB or Content Providers. For more information refer this link

Ali Behzadian Nejad
  • 8,804
  • 8
  • 56
  • 106
  • 1
    I have two devices, a HTC Desire and a Samsung Galaxy Nexus. With the Desire I don't get the error. With The Galaxy Nexus I do. – Timon Devos May 04 '12 at 10:59
11

to find such problems just enable StrictMode for Debug Version like that:

public void onCreate() {
     if (DEVELOPER_MODE) {
         StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                 .detectDiskReads()
                 .detectDiskWrites()
                 .detectNetwork()   // or .detectAll() for all detectable problems
                 .penaltyLog()
                 .build());
         StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
                 .detectLeakedSqlLiteObjects()
                 .detectLeakedClosableObjects()
                 .penaltyLog()
                 .penaltyDeath()
                 .build());
     }
     super.onCreate();
 }

more information @ http://developer.android.com/reference/android/os/StrictMode.html

all the best,

cV2
  • 5,229
  • 3
  • 43
  • 53
4

Always, remember to close the cursor by calling cursor.close() before closing the database. That should fix your problem.

Vincy
  • 1,078
  • 1
  • 9
  • 16
0

let the activity manage the cursor lifecycly by using startManagingCursor(c) and it will be fine.

Akhil
  • 13,888
  • 7
  • 35
  • 39
  • Where do I write this? Because in my DatabaseAdapter class (extends SQLiteOpenHelper) he doesn't find "startmanagingcursor()" – Timon Devos May 04 '12 at 11:01
  • its a method of Activity.for example you are getting a cursor from your DBAdapter and setting it to a listview inside an Activity.Inside the activity, call startManagingCursor(c) before giving to setAdapter()..; – Akhil May 04 '12 at 11:06
  • I work with an ArrayAdapter. So I don't return the cursor but an array instead. How do I need to solve it with an arrayadapter? – Timon Devos May 04 '12 at 11:12
  • In the constructor of your ArrayAdapter: Activity a =(Activity)ctx; a.startManagingCursor(c); – Akhil May 04 '12 at 11:21
  • It's an ArrayAdapter there is no cursor. – Timon Devos May 04 '12 at 12:14
  • your question is about cursor lifecycle. – Akhil May 04 '12 at 13:44
  • 1
    Yes of course there's a cursor. But the cursor I use is in the DatabaseAdapter class(A class with all methods to get/add/remove data from database). I use an ArrayAdapter to populate my ListView. So I get the data from the database with a cursor and put that into an arraylist wich I return and give to the ArrayAdapter. So no Cursor in the ArrayAdapter – Timon Devos May 04 '12 at 13:50
  • I'm in the same position with an ArrayAdapter populating the ListView. If you find a solution, please do share... – brandall May 21 '12 at 17:40
  • The solution is very simple. If you use the cursor manipulation using an Activity then use its built in Managers like StartManagingCursor() and StopManagingCurosr() methods. But if you have the cursor manipulation outside the activity then the moment you're done with iterating the cursor and extracted all the data that you needed, call the cursor.close() method. As you may know, it is case sensitive so find the exact cases. For example if you declared your Cursor as cursor then you can use cursor.close(). To be safe I also say cursor = null; :) – Vincy Feb 26 '13 at 13:26
  • 1
    Just say your code; so in your case just before db.close() call the cursor.close() that's it. So the code sequence is cursor.close(); cursor = null; db.close(); – Vincy Feb 26 '13 at 13:40