Android StrictMode reporting false positives - android

I have been trying to run my application in StrictMode to check for any hidden problem that may have sneaked. One issue I ran across is what seems to be a false positive of Leaked DatabaseConections when using ContentResolver.
After some experiments got the issue simplified to the following 2 lines of code:
Cursor c = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, cols, null, null, MediaStore.Video.Media.DEFAULT_SORT_ORDER);
c.close()
The 2 lines above generate the following StrictMode violation:
ERROR/StrictMode(26219): Releasing cursor in a finalizer. Please ensure that you explicitly call close() on your cursor:
ERROR/StrictMode(26219): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
ERROR/StrictMode(26219):
at android.database.CursorWindow.<init>(CursorWindow.java:62)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:403)
at android.content.ContentResolver.query(ContentResolver.java:302)
I am assuming that this is something specific to the fact that the Cursor was returned by a contentProvider (so it is not a direct SQLite cursor).
Does anyone have any insight if this is indeed a false positive or there is really a leaky cursor.

I think I can explain where the problem is.
When you query database you can receive an exception. Thus, a Cursor will be created c.close() will not be called because there is an exception. Thus, you have to put the creation of the Cursor in try catch block and close the curson in the finally block.

Related

Proper way of using sqlite insertOrThrow

My code looks something like this:
ContentValues values = new ContentValues();
values.put("year", year);
values.put("month", month);
database.insert(MySQLiteHelper.TABLE_DATA, null, values);
Everything works fine, but unfortunately the insert query will always return -1 on one of my user's device. My app has bugsnag so now I changed the
insert
to
database.insertOrThrow
hoping that when an error occurs on the user's phone again, bugsnag will notify me. BUT just to make sure (since I've never used insertOrThrow before; usually just insert encapsulated in try catch), is the code above sufficient? When an error happens on insert, will bugsnag capture it? Maybe my question can be summarized as 'how do I handle throw in insertOrThrow?'
insertOrThrow throws a SQLException in the event of an error, which is a subclass of RuntimeException.
Bugsnag will automatically handle any uncaught exceptions in your app by registering a Thread.UncaughtExceptionHandler, so you shouldn't need to do anything else to capture the event.
Make sure you are putting all the values that you have been declared during creating the table in my case that solve the problem.

Android effectively cursor usage?

In my Android activity, I use rawquery many times. And I use a static cursor for that rawquery. My question is: should i close my cursor before execute another rawquery or just leave it open til all the rawqueries are executed (close only once).
I try both and the result is the same. But in term of performance/debug, which one is better?
you should close your cursor after finishing with it. otherwise you will consume all the allowed cursor resources for your application (it is limited) and will get an exception.
making static does not make it one open cursor for all. remember that it is static on the java side; there is a native side here that uses new resources for each opened cursor. you need to free these resources.
If you don't close the cursor after each use, you are leaking memory quite badly. What you are actually doing is creating a new cursor with every query, but using a single static reference to refer to only the newest. (References to the older cursors are lost.)
Unclosed cursors can also cause fatal errors further down the line, if (for example) the runtime tries to do some garbage collection. The SQLiteDatabase's finalize() method (called on garbage collection) will throw an exception if it notices that some cursors are still open, and this can kill your app.

Using the same database in successive activities in Android without memory leak

I'll preface this question with the note that I have looked at this similar question, but I'm still encountering issues. Basically, I want to access the same database in two activities in my Android application. However, when I open it in the second activity, I'm getting two series of messages in my LogCat:
First:
"Uncaught exception thrown by finalizer (will be discarded):
Ljava/lang/IllegalStateException;: Finalizing cursor android.database.sqlite.SQLiteCursor#436053b8 on dogs that has not been deactivated or closed
at android.database.sqlite.SQLiteCursor.finalize(SQLiteCursor.java:596)"
(dogs is the name of a table in my database, dog_data)
Second:
"ERROR/Database(1316): Leak found
ERROR/Database(1316): java.lang.IllegalStateException: /data/data/com..../databases/dog_data SQLiteDatabase created and never closed"
As far as I can tell, I am closing my database upon exiting the first activity. Following the style of the notepad tutorial, I have a wrapper class "DbAdapter" around my SQLiteDatabase, and in the onPause() method of the first activity, I call the close method on that Adapter (which calls the close methods on my SQLiteDatabase and my SQLiteOpenHelper).
I think the issue is how I am trying to reopen the database in my second activity:
SQLiteDatabase db = openOrCreateDatabase("dog_data",
SQLiteDatabase.CREATE_IF_NECESSARY, null);
(I choose not to use a wrapper because I only needed to run one query on the database, perhaps this is an issue).
Can someone advise as to where my issue might be? I'll admit (as may be clear from my question) that I don't fully understand the implications of "closing" a database (the documentation for SQLiteDatabase.close() is not particularly specific), which is probably the main reason for my problem.
Thanks.
Just in case someone happens to encounter a similar issue (seems possible but probably unlikely), I recently stumbled onto the solution. In the insert method of my "DbAdapter", I was (stupidly) checking uniqueness via a query for a row with a given value for one of the fields, and seeing whether that query returned any rows. This was creating a cursor that I wasn't closing, which resulted in the "Finalizing cursor" error noted above.
I've received that error before and had to use cursor.close() to correct the issue. I'm not exactly sure why because there are times when I didn't use close() and received no error. Maybe it's a warning that only gets noticed when it is sitting next to a show stopping error?
I will say the proper procedure is open database connection -> create cursor by running db method -> iterate through cursor -> close cursor -> close database connection.

Can't find the source of a DatabaseObjectNotClosedException error

I'm having a hard time figuring out what my problem is here. I'm receiving this error in my program, but it does not cause a crash or anything like that. I have an update I'd like to release, but I don't want to release it with this error being thrown at certain times. I've read all related posts on this error, but none apply to my situation.
I've made sure that I am closing my DatabaseHelper and SQLiteDatabase objects. I've also made sure that I'm closing all of my cursors. This error is pointing toward my method getActiveScheduleInfo, which returns a Cursor object. I've made sure that whenever I call this method, the returned cursor is closed in a Finally block.
Is this incorrect to do it this way? In my methods that call getActiveScheduleInfo, I have multiple return statements in them, based on certain conditions. So, instead of closing the cursor before each return line, I surround the condition testing with a Try, and close everything down in my Finally.
Everything looks like it should be working, so I'd really appreciate any help!
Thanks a lot!
Paul
I was able to figure this out! I hope that this helps someone else out there having the same problem.
I wasn't doing anything inherently incorrect here, but was rather taking too long to close some of my cursors. To give you a very brief background, I could not use a Managed Query or use startManagingCursor, since this code was in a custom class, not an activity. I am building against Android 2.0 (API level 5) so I am not using the new CursorLoader object.
I was taking the following steps:
Opening the database.
Creating a new Cursor and performing my query.
Iterating through the cursor and performing the needed tasks
Performing some other logic
Closing the Cursor and Database in a Finally block.
I found out that my step 4, performing some other logic, coming before closing my Cursor, was causing it to, for lack of a better term, timeout and cause this error. From now on, I read the necessary data from the Cursor, and not ONE LINE OF CODE FURTHER, I close the Cursor. :) This has completely eliminated these random errors, and I have clean-running code again.
I hope that helps others having the same problem! Take care,
Paul

Viewing an Android database cursor

Would anyone know how I can view what a cursor has in it during debugging so that I can determine the functionality of my database helper?
It keeps acting like it's returning data, but then when I attempt to use the cursor.isNull(0) method, I keep getting NullPointerException thrown and not being able to see what the cursor has in it while stepping through the execution is really frustrating me.
Any help would be extremely appreciated.
Thanks.
Android has provided a specific class just for debugging Cursors. It is called DatabaseUtils.
Call the method DatabaseUtils.dumpCursorToString(cursor) to view the contents of your cursor.
This helper loops through and prints out the content of the Cursor for you, and returns the cursor to its original position so that it doesn't mess up your iterating logic.
If that's null pointer exception, it seems your cursor really is null.
I would use Log.d() to help debug my cursors, you can simply create a helper method to dump the whole row of your cursor to LogCat.

Categories

Resources