Android & SQLite - Occasional error 'unable to close due to unfinalised statements' - android

I seem to get the above error every so often in (an insert heavy) part of my code. I know normally this means there is an open Cursor within the connection but I have been through checking all my cursors are in try finally blocks and closed.
Also in logcat the error reads 'sqlite3_close(...) failed: 5 which I think means the database is busy?
The error can be 'ignored' if I add the following code to my finally block where the database connection is closed.
finally
{
writer.endTransaction();
boolean successAtClose = false;
while(successAtClose == false)
{
try
{
writer.close();
successAtClose = true;
}
catch(Exception e)
{
e.printStackTrace();
}
}
dbConn.releaseLock();
}
When stepping through the code above the 'e.printStackTrace()' is hit once but on the second attempt the 'writer.close()' does not throw an error.
Just to reiterate, this problem doesn't even happen every time the code block runs, the same data can be inserted say 5/6 times and only throw the error on one of these times. In addition the error does not reoccur straight away after happening once but continues to pop-up at random intervals.
Does anyone know why this might occur? Or a better way to recover from this than the finally code above? (Since it will take me a long time to add this to all my database code.)
ADDED:
Database is opened with a custom SQLiteOpenHelper which is extended to use a reentrant lock to ensure only one thread accesses the database at any one time. So the start of the code is like:
MyDatabaseHelper dbConn = MyDatabaseHelper.getDatabaseAccess(c);//await availability/lock the database here
SQLiteDatabase writer = dbConn.getWritableDatabase();
try
{
writer.beginTransaction();
//do inserts
writer.setTransactionSuccessful();
Get database access as follows:
public static MyDatabaseHelper getDatabaseAccess(Context c)
{
l.lock();
return new MyDatabaseHelper(c);
}
As a further test I have further added a Thread.sleep() call to the finally code (in my case of 12 seconds), before the close() but after the endTransaction(), that seems to have stopped the error and confirm it is not a case of an open cursor, but I would rather not rely on a timer. If there is a better way, perhaps to pre-check whether the database is busy, please share.

If you are using SQLiteStatement or SQLiteQuery objects to work with your database you need to make sure they get closed out as well. If it's SQLiteClosable you need to close it.

This mainly happens when you haven't closed the cursor, meant certain references to the database were invalid.
refer ths link Android SQLite Exception: unable to close due to unfinalised statements

The workaround is incorrect. close() decrements a reference counter and only when the counter hits exactly zero is the actual resource disposal i.e. sqlite3_close() attempted. On the second call the counter will be negative and the call will be a no-op.
You are correct that error code 5 is SQLITE_BUSY.
Now to address the actual problem, please provide some additional details, such as how you open and configure the database and how you begin your transactions.

Related

Is closing a database opened with window.openDatabase necessary?

The code at the moment reads something in the order of...
DoAnything() {
OpenTheDatabase()
// ... Do all the things! ...
}
However, the database object is never closed. This is worrisome.
The database is opened as follows:
var db = window.openDatabase( ... paramters ... );
No .closeDatabase function exists, or the documentation is incomplete. I thought the following might suffice:
db=null;
I see that sqlite3_close(sqlite3*) and int sqlite3_close_v2(sqlite3*) exist, but I'm unsure how to apply them in this case.
How do I close the database, and is it necessary?
Generally you only have one database connection that you open on app startup, and there is no need to close it while the app is open. It's a single threaded, single user app, so a lot of the normal rules about database connections don't apply.
When the app shuts down, you can rely on the browser to close everything - given the average quality of code on the web, browsers have to be pretty good at cleanup.
Setting db to null and letting the garbage collector do its thing will probably also work, but it is better not to create the extra objects in the first place.

How to over come database not opened exception?

I am implementing an app related to database.
So many times I am calling open and close database connection to insert, update and delete.
It is working fine.
But some times I am getting a database not opened exception in different situations.
How to solve these issues?
Well unless you put proper exception handling you would never know what causes this.
However a good idea is to adopt good ORM mapper for SQL Light with Android and this will improve your database interactions and exception handling and opening and closing it efficiently.
You can opt for SUGAR or ORMLight if you wish; In my opinion this should help you to fix your problem.
Based on the information you provided I can assume that the problem is in your business logic and nobody but you should be able to tell you the root cause.
Without your code here, we won't be able to point you to exact place.
One of the possible reasons can be that by your business logic you are trying to do some operation (insert, update whatever) on closed database.
You can do some workaround to try to ensure that your DB is always open when it is needed. If you implement database getter method with so called lazy initialization approach it will guarantee at least, that the DB is open when you need to access it.
Here is what I am talking about:
1. make a public method which supposed to return DB object:
public SQLiteDatabase getDB() {
if ((mDataBase == null) || (!mDataBase.isOpen())) {
// create or open your database using an OpenHelper
mDataBase = SQLiteOpenHelper.getWritableDatabase();
}
return mDataBase;
}
Now, everywhere in your code use this method to access the DB instead of directly accessing a variable mDataBase.
Note that the code is just to give you an idea and not actually compilable.
Still, I would recommend you to fix your business logic instead of using this workaround.

Using multiple methods in a transaction

I'm making an Android app, which gets its information from XML files.
I'm filling the information in a database, for easier acces during the program's runtime, thanks to the power of queries.
However it came to my attention, that using Transactions greatly improves speed, so naturally, I want to use that.
My problem is the following tho;
In the idea of abstraction, after parsing all the information of one subject, the information gets send to the correct entity (class), and inside that entity there is a method that will add it in the database. After that, it returns to the parser which continues to read the next subject, which in it's turn will be send to right (and probably different) class again.
This is implemented with a switch statement, with every case pointing to a different class constructor.
If I want to use the speed of transactions, I would need to start a transaction already before the parsing, run through the parsing and query building (as far as I understand, all queries build within the transaction, are collected and in the end all executed as a bunch) and then end the transaction, once the whole file is parsed.
To make this a bit clearer, or faster to read; The code idea would be;
Class parser(){
database.beginTransaction();
try{
// start parsing in a whole different class, which also points to SQL queries (in different classes again) in the entitys with a switch
}catch(Exception e){
database.endTransaction();
}
database.endTransaction();
}
I hope i formulated my question clearly enough.
Kind regards,
Yes, you've got the general idea. However, you need to be careful to mark the transaction as successful when you finish parsing, and also to ensure the transaction is always closed even in the event of an exception.
Example from the docs:
db.beginTransaction();
try {
// do all the parsing in here
...
db.setTransactionSuccessful();
} finally {
db.endTransaction();
}

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

Categories

Resources