Sqlite Connection Leaked Although Everything Closed

SQLite Connection leaked although everything closed

The bolded font in the citation corresponds to this part in your code:

private DatabaseManager open() throws SQLException {
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();

from: http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html

Approach #1: Use an Abstract Factory to Instantiate the
SQLiteOpenHelper

Declare your database helper as a static instance variable and use the
Abstract Factory pattern to guarantee the singleton property. The
sample code below should give you a good idea on how to go about
designing the DatabaseHelper class correctly.

The static factory getInstance method ensures that only one
DatabaseHelper will ever exist at any given time. If the mInstance
object has not been initialized, one will be created. If one has
already been created then it will simply be returned.


You should
not initialize your helper object using with new DatabaseHelper(context).

Instead, always use
DatabaseHelper.getInstance(context), as it guarantees that only one
database helper will exist across the entire application's lifecycle.

public static class DatabaseHelper extends SQLiteOpenHelper { 

private static DatabaseHelper mInstance = null;

private static final String DATABASE_NAME = "database_name";
private static final String DATABASE_TABLE = "table_name";
private static final int DATABASE_VERSION = 1;

public static DatabaseHelper getInstance(Context ctx) {

// Use the application context, which will ensure that you
// don't accidentally leak an Activity's context.
// See this article for more information: http://bit.ly/6LRzfx
if (mInstance == null) {
mInstance = new DatabaseHelper(ctx.getApplicationContext());
}
return mInstance;
}

/**
* Constructor should be private to prevent direct instantiation.
* make call to static factory method "getInstance()" instead.
*/
private DatabaseHelper(Context ctx) {
super(ctx, DATABASE_NAME, null, DATABASE_VERSION);
}
}

Sqlite connection Leaked in android studio despite everything is closed

There are multiple things you did wrong in the getQuestionMode method. Those being:

  • closing the db connection after reading the first item
  • closing cursor outside finally block

Also, I would avoid this line if (c == null) return null;.

I would recommend using singleton pattern to access data.

To fix your current issue try this:

public List<Question> getQuestionMode(String mode) {
List<Question> listQuestion = new ArrayList<>();
SQLiteDatabase db = this.getWritableDatabase();
Cursor c = null;
int limit = 0;
if (mode.equals(Common.MODE.EASY.toString()))
limit = 20;
else if (mode.equals(Common.MODE.MEDIUM.toString()))
limit = 20;
else if (mode.equals(Common.MODE.HARD.toString()))
limit = 30;
else if (mode.equals(Common.MODE.HARDEST.toString()))
limit = 30;

try {
c = db.rawQuery(String.format("SELECT * FROM Question ORDER BY Random() LIMIT %d", limit), null);
if(c.moveToFirst()) {
do {
int Id = c.getInt(c.getColumnIndex("ID"));
//int cid= c.getInt(c.getColumnIndex("C_ID"));
String Qus = c.getString(c.getColumnIndex("Qus"));
String AnswerA = c.getString(c.getColumnIndex("AnswerA"));
String AnswerB = c.getString(c.getColumnIndex("AnswerB"));
String AnswerC = c.getString(c.getColumnIndex("AnswerC"));
String AnswerD = c.getString(c.getColumnIndex("AnswerD"));
String CorrectAnswer = c.getString(c.getColumnIndex("CorrectAnswer"));

Question question = new Question(Id, Qus, AnswerA, AnswerB, AnswerC, AnswerD, CorrectAnswer);
listQuestion.add(question);
}
while (c.moveToNext());
}

} catch (Exception e) {
e.printStackTrace();
} finally {
if(null != c)
c.close();
if(null != db)
db.close();
}

return listQuestion;
}

Update:

You still have an open database in openDataBase() method. Also add finally block to checkDataBase().

You could try rewriting your helper to this(See the example!).

Unable to prevent SQLiteConnection object leakage

You say you looked into many questions online, but you definitely didn't look into this or this. It literally cropped up 5 minutes into searching.

Anyways, if I were you, to resolve this issue, I would include a finally clause when closing the connection. This means that you would be declaring your database helper as a static instance variable and use the Abstract Factory pattern to guarantee the singleton property.

Your warning is happening because you are not ensuring that only one DatabaseHelper will ever exist at any given time. If the mInstance object has not been initialized, one will be created. If one has already been created then it will simply be returned.

Here is the code:

public ArrayList<ItemSubject> loadDataSubject() {
ArrayList<ItemSubject> arrayList = new ArrayList<>();
String select = "select * from " + TABLE_SUBJECT;
Cursor cursor = getData(select);


if (cursor != null && cursor.getCount() > 0) {
try {
cursor.moveToFirst();
for (int i = 0; i < cursor.getCount(); i++) {
String id = cursor.getString(cursor.getColumnIndex(TAG_ID));
String course = cursor.getString(cursor.getColumnIndex(TAG_COURSE_NAME));
....
ItemSubject objItem = new ItemSubject(id, courseId,...);
arrayList.add(objItem);
cursor.moveToNext();
}
finally {
if (cursor != null)
cursor.close();
}
}
return arrayList;
}

But since you say that my only contribution to your question (which had already been answered in other posts) is that of refining your lack of elementary English, then I am not that sure if you can accept this as an adequate answer.

SQLite Android Leaked

you are not closing db_writer

Regardless of not using it, you still open it at the intialisation.

    this.db_writer = bd.getWritableDatabase();

It is recommended to close it also, else the connection is leaked.

   this.db_writer.close();

Better yet would be to write a helper method that you can call:

public void CloseDb()
{
if(db_writer.isOpen())
db_writer.close();
if(db_reader.isOpen())
db_reader.close();

}

You can then call CloseDb() where appropriate (still need to close cursors as per normal).
This method checks its open before closing, so does not try to close it twice.

You do not normally close a Databasehelper from within itself though. Usually once you have finished using it in an from an activity. (Call CloseDb() from your activity once you have finished, aka, onPause or onDestroy.)

Android SQLite leaked

Each Cursor should be closed when you're finished with it. The traditional way to do this is:

Cursor cursor = db.query(...);
try {
// read data from the cursor in here
} finally {
cursor.close();
}

But now, with try-with-resources, it can be much more concise:

try (Cursor cursor = db.query(...)) {
// read data from the cursor in here
}


Related Topics



Leave a reply



Submit