I've got my database connection setup in an Application but LogCat keep's telling me about a SQLite leak
04-25 11:22:23.771: W/SQLiteConnectionPool(9484): A SQLiteConnection object for database '+data+data+com_appstart+databases+database' was leaked! Please fix your application to end transactions in progress properly and to close the database when it is no longer needed.
I'm starting to wonder if it is down to how I'm using the database adapter.
I attach my code...
This is my code where some times i found and error..
try{
DBAdapter dba = new DBAdapter(this);
dba.open();
Cursor c = dba.getModules(Constant.LANGUAGE_ID);
for (int i = 0; i < c.getCount(); i++) {
if (i > 2) {
a.add(c.getString(2));
moduleid.add(c.getString(0));
icon_name.add(c.getString(1));
System.out.println(c.getString(2) + "------" + c.getString(0));
}
c.moveToNext();
}
c.close();
dba.close();
}catch(Exception e){
e.printStackTrace();
}
this is my DBAdapter class that contains Open() and Close() methods.
public DBAdapter open() throws SQLException {
db = DBHelper.getWritableDatabase();
return this;
}
public void close() {
DBHelper.close();
}
What is this DBAdapter class you're using? I don't know what it's doing so I don't know if it's correct. You should check where the SQLiteConnection object is obtained that the error message refers to, and ensure that that SQLiteConnection is close()d.
Are you getting the error only occasionally or all the time? It's probably not the main problem you are observing, but your code also fails to call close() when there is an exception before the close(). You should ensure close() gets called regardless of exception path by guarding it with a try/finally block:
dba.open();
try {
Cursor c = ...;
try {
...
} finally {
c.close();
}
} finally {
dba.close();
}
Your problem is that you have to "Close" the database once you finished your database operation. So close your DB wherever you opened your DB.
in DBAdapter class, in close function replace DBHelper.close() from db.close();
public void close() {
DBHelper.close();
}
replace with the below;
public void close() {
db.close();
}
public DBAdapter open() throws SQLException {
db = DBHelper.getWritableDatabase();
//You should close the opened database
DBhelper.close
return this;
the same also goes for cursor once you opened it it needs to be closed.
Related
I used to have a database and there was no error , My database comes from the asset folder , it's already coded with SQLCipher
after that ,in all of my activities I get this error that the cursor or database is open and didn't closed .
#Override
protected void onCreate() {
super.onCreate();
myDb = new DBAdapter(this);
myDb.open();
cursor = myDb.getFavorits();
}
#Override
protected void onDestroy() {
super.onDestroy();
myDb.close();
cursor.close();
}
#Override
protected void onStop() {
super.onStop();
myDb.close();
cursor.close();
}
this is DBAdapter class where it opens and closes :
public void open() {
SQLiteDatabase.loadLibs(context);
File databaseFile = context.getDatabasePath("mydb");
db = SQLiteDatabase.openOrCreateDatabase(databaseFile,"mypass", null);
}
public void close() {
Log.v("this","dbclose");
db.close();
}
public Cursor getFavorits() {
Cursor c = db.query(DATABASE_TABLE, ALL_KEYS, null, null, null, null,null, null);
if (c != null) {
c.moveToFirst();
}
return c;
}
but when I leave this activity , it shows me this errors :
Finalizing a Cursor that has not been deactivated or closed. database = /data/data/pachagename/databases/mydb, table = null, query = SELECT _id from favorits
07-06 15:42:42.769: E/Cursor(1214): net.sqlcipher.database.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
could you help me to find out and solve this problem ?
Update :
Something new I notice now , when I enter the activity and without leaving the activity ,it shows me this error !! what should I do ?
onDestroy is called after onStop. I believe you are trying to close something that is already closed. Try to leave only the super.onDestroy(); in your onDestroy method
EDIT: Just a shot in the dark:
What happens when you change getFavorits() to private static method and call it from onCreate like this: cursor = DBAdapter.getFavorits() ?
I believe that your issue is that you are closing the database before closing the Cursor. The Cursor should be closed before the database as the cursor accesses the database.
I'm trying to implement android SQLite usage design pattern that ensures one opened SQLiteDatabase instance per application.
public class BaseDataSource {
private static final CustomSQLiteHelper dbHelper = CustomSQLiteHelper.getInstance();
protected static SQLiteDatabase database;
static {
//HERE RISES EXCEPTION
BaseDataSource.database = BaseDataSource.dbHelper.getWritableDatabase();
}
private void close() {
if(null != BaseDataSource.database && BaseDataSource.database.isOpen()) {
BaseDataSource.database.close();
if(null != BaseDataSource.dbHelper) {
BaseDataSource.dbHelper.close();
}
}
}
protected BaseDataSource() {}
protected void finalize () throws Throwable {
close();
super.finalize();
}
}
But while my applications starts I get this kind exception:
Caused by: java.lang.IllegalStateException: attempt to re-open an already-closed object: SQLiteDatabase: /data/data/com.xxx/databases/xxx.db
How SQLiteDatabse database can be opened and closed before class was created?
UPDATED
I found my own bug. It was in CustomSQLiteHelper class. In onCreate method I closed database. I tried every soliution that I found in internet and due to that I made a bug.
if you going to event any thing then first need to open as write database. So for that use this method
and call like this
openAsWrite();
public void openAsWrite() throws SQLException {
db = DBHelper.getWritableDatabase();
}
// ---closes the database---
public void close() throws SQLException {
DBHelper.close();
}
Use following pattern when getting a database object:
try {
if (sDatabase != null) {
if (!sDatabase.isOpen()) {
sDatabase = sContext.openOrCreateDatabase(DATABASE_NAME, 0, null);
}
} else {
// open database here
sDatabase = sContext.openOrCreateDatabase(DATABASE_NAME, 0, null);
}
Log.d(TAG, "Database successfully opened.");
} catch (SQLException e) {
Log.e(TAG, "" + e);
}
Using database object as static makes your class behave like this.
Creates database instance when the class is loaded.
closes the database connection when finalize method is called.
your class will not going to acquire database connection anymore, and it will have the database instance which is closed already.
eventually when try to access the instance which is closed, it pops the error to you
I think you should use a different approach will be better.
I'm using a single sqlite database throughout my app. So I want to wrap a connection to the db in a singleton for convenience. At first I thought I could keep a reference to the SQLiteDatabase around for that:
MySQLiteOpenHelper helper = new MySQLiteOpenHelper(appContext); // local
myGlobalSQLiteDatabase = helper.getWritableDatabase(); // global
...
void someFunction() {
try {
myGlobalSQLiteDatabase.insertOrThrow(...);
} catch (Exception ex) {
}
}
but this would result in errors such as:
(1802) os_unix.c:30011: (2) stat(/data/data/com.me.test/databases/test.db) -
(1802) statement aborts at 16: [INSERT INTO mytable(f1,f2) VALUES (?,?)]
android.database.sqlite.SQLiteDiskIOException: disk I/O error (code 1802)
at android.database.sqlite.SQLiteConnection.nativeExecuteForLastInsertedRowId(Native Method)
at android.database.sqlite.SQLiteConnection.executeForLastInsertedRowId(SQLiteConnection.java:775)
...
(this is all being done on the main thread, a single test).
My second attempt was to instead keep a global reference to the helper only:
myGlobalSQLiteOpenHelper helper = new MySQLiteOpenHelper(appContext); // global
...
void someFunction() {
SQLiteDatabase db = myGlobalSQLiteOpenHelper.getWritableDatabase();
try {
db.insertOrThrow(...);
} catch (Exception ex) {
} finally {
db.close();
}
}
and that works. I have to call getWritableDatabase() and close() on each call of someFunction().
I don't know how much overhead there is in getWritableDatabase() and close(), I was originally hoping for the fastest implementation possible, as I'll be calling someFunction() repeatedly in response to user input. Is the second method the best option for this setup?
Thanks
You don't need to write getwritable database again and again just make a constructor of db class public DBCustomer open() throws SQLException
{
db = DBHelper.getWritableDatabase();
return this;
}
and call all the function of db just decalring object and calling object.open function
I'm getting two contradicting Exceptions when creating and populating my new SQLiteDatabase in Android. In short my code:
SQLiteOpenHelper extending class:
public void onCreate(SQLiteDatabase db) {
db.execSQL(DB_TABLE_CREATE);
loadLevelData(db); //puts data in the database
//db.close(); <<< ?
}
In my activity class I instantiate this class (in onCreate()), and call getWritableDatabase():
dbHelper = new DbOpenHelper(getApplicationContext());
database = dbHelper.getWritableDatabase();
Now if I don't call db.close() after populating the database, like above, I get
android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
However if I DO close it, I get the following exception:
java.lang.IllegalStateException: database not open
on getWritableDatabase().
This really confuses me, so could anyone help me with what's wrong?
You are not expected to close the database in the DatabaseHelper class. However you need to close it every time you open it calling getWritableDatabase:
dbHelper = new DbOpenHelper(getApplicationContext());
database = dbHelper.getWritableDatabase();
//... do something with database
database.close();
You are closing your database at the wrong time.
I typically keep the database around like this:
public class MyActivity extends Activity {
SQLiteDatabase writeableDb;
// ...
// Code
// ...
public void onStart(){
super.onCreate(savedState);
// Do stuff, get your helper, etc
writeableDb = helper.getWriteableDatabase();
}
public void onStop(){
writeableDb.close();
super.onStop();
}
}
Alternatively, wrap all your code working with that db connection in a try/finally block
db = helper.getWriteableDatabase();
try { // ... do stuff ... }
finally { db.close(); }
Note: All of the opening/closing should be done in the Activity working with the database, not the open helper.
I have been learning (slowly but surely) how to do deal with sqlite databases on android systems. Using information I found here:
http://mfarhan133.wordpress.com/2010/10/24/database-crud-tutorial-for-android/
I have learned how to create, load things into and retrieve information from a database on my android system. One of the hitches was this method here:
public Cursor getClientsCursor() {
StudioTabOpenHelper dbAdapter=StudioTabOpenHelper.getDBAdapterInstance(this.getListView().getContext());
try {
dbAdapter.createDatabase();
} catch (IOException e) {
Log.i("*** select ",e.getMessage());
}
dbAdapter.openDataBase();
String query="SELECT * FROM CLIENTS;";
Cursor c = dbAdapter.selectRecordsFromDB(query, null);
//dbAdapter.close();
return c;
}
The problem was that the above code was closing the adapter I had opened...this was causing the part where I used that returned cursor to complain that database conn#0 already closed. So I commented out that dbAdapter.close(); I think this is bad in the future if i call this method again.
So my question is: Should I at the start of my application create the dbAdapter and open the database and leave it open and never close it? (how do i pass the dbAdapter around to activities, fragments etc if I go this route) ... or how can I use the getClientsCursor method as is and figure out some other way to pass back the cursor and be able to call the .close()?
/**
* Open the database
* #throws SQLException
*/
public void openDataBase() throws SQLException {
String myPath = DB_PATH + DATABASE_NAME;
myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE);
}
/**
* Close the database if exist
*/
#Override
public synchronized void close() {
if (myDataBase != null)
myDataBase.close();
super.close();
}
My adapter code was gotten from here:
http://mfarhan133.wordpress.com/2010/10/24/database-crud-tutorial-for-android/
I just didn't call my class DBAdapter but called it StudioTabOpenHelper.
You may close your adapter on the
onDestroy() method of your activity.