with simple below code i get this error for close database or cursor:
Database﹕ close() was never explicitly called on database '/data/data/ir.tsms/databases/tsms'
android.database.sqlite.DatabaseObjectNotClosedException:
My Function:
public Boolean searchLastID( Long lastID){
SQLiteDatabase db = this.getReadableDatabase();
String selectQuery = "SELECT * FROM " + this.RECEIVE_FIELDS_TABLE + " WHERE lastId = ?" ;
String[] args = {String.valueOf(lastID)};
Cursor cursor = db.rawQuery(selectQuery, args);
//db.close();
return cursor.moveToFirst();
}
after uncommenting db.close();
Cursor﹕ Finalizing a Cursor that has not been deactivated or closed. database = /data/data/ir.tsms/databases/tsms, table = null, query = SELECT * FROM ReceiveFields WHERE lastId = ?
whats problem and how to resolve that? i can't find any document about this problem. Thanks
make your cursor a global variable
and inside your onDestory Method close your cursor and your database
#Override
protected void onDestroy() {
super.onDestroy();
cursor.close();
db.close();
}
As soon as you're done retrieving the data of your query from your database you should close the Cursor or at least deactivate it. (Keyword: Freeing resources)
Following two quotes from the Docs on the close() and deactivate() method:
#close()
Closes the Cursor, releasing all of its resources and making it
completely invalid. Unlike deactivate() a call to requery() will not
make the Cursor valid again.
#deactivate()
Deactivates the Cursor, making all calls on it fail until requery() is
called. Inactive Cursors use fewer resources than active Cursors.
Calling requery() will make the cursor active again.
Related
I've implemented a sqlite database in my application and I'm using the Android Cursor. I've written a database class with e.g. the database name and the table and column names. Here I also have various methods, like the following:
public Cursor getCorrectQuestions(int topic) {
SQLiteDatabase db = getReadableDatabase();
Cursor questionCursor = db.rawQuery(
"Select * FROM Result, Question WHERE Result.qid = Question._id AND correct = 1 AND topic = " + topic,
null);
questionCursor.moveToFirst();
return questionCursor;
}
public Cursor getExamQuestions() {
SQLiteDatabase db = getReadableDatabase();
Cursor questionCursor = db.rawQuery("Select * FROM Question WHERE topic = 7", null);
questionCursor.moveToFirst();
return questionCursor;
}
public Cursor getAnswerItems(String id) {
SQLiteDatabase db = getReadableDatabase();
Cursor answerCursor = db.rawQuery(
"Select * FROM Answer, Question WHERE Question._id = " + id + " AND Question._id = Answer.qid", null);
answerCursor.moveToFirst();
return answerCursor;
}
public Cursor getUserResults(String qid) {
SQLiteDatabase db = getReadableDatabase();
Cursor userResultsCursor = db.rawQuery("SELECT result FROM Result, Answer WHERE Result.qid = " + qid, null);
userResultsCursor.moveToFirst();
return userResultsCursor;
}
In the QuizActivity which has 3 cursors (answerCursor, questionCursor, userResultCursor) I call these methods.
My question is: is it necessary to create a SQLiteDatabase Object in every method or is it possible to define this once in my database constructor? And do I need 3 different cursors in my activity or is there a better way to handle this?
Assuming the methods you have written are part of a SQLiteOpenHelper, you are not really creating 3 database objects. Only the first call to getReadableDatabase() actually creates a database object, and subsequent calls reuse the same object over again.
You also need to make a new Cursor for each query you perform, as they cannot be edited after creation. In this sense, there is no way to simplify what you have already done.
As far as improvements to your code, there are a few things you can look at:
Consider putting your database in a ContentProvider and accessing it via URI's. This will require more upfront work, but will make it much easier if you want to share your database with other apps or sync your data to a server in the future.
Leave the cursor in its default position (don't call moveToFirst()). That way when the caller receives the cursor, it can use the following code to start iterating cursor rows without performing any further checks:
while (cursor.moveToNext()) {
// extract data
}
This is because the cursor returned from a query is initially positioned before the first row of data, so if the cursor is empty then the code inside the while loop simply never executes at all.
In my DatabaseHelper class that extends SQLiteOpenHelper I've set various methods to return Cursors to my other Activities so that I don't perform any queries within any other class except DatabaseHelper. In those methods I don't close the Cursor or database afterwards, and I return it like:
public Cursor getCoursesLeft()
{
// Open a readable database.
SQLiteDatabase database = this.getReadableDatabase();
// Query the database and return the cursor.
return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}
From whichever Activity I call the method from, I do ensure to close the Cursor that's returned after I use it.
Since Cursor is an Object, it should pass by reference, correct? So closing it from the other Activity should close the original object, and if I understand it correctly closing the Cursor also closes the database.
Is this a bad coding practice?
It seems like randomly I'll get a LogCat error saying close was never called on the database and the only thing I can find in my code that might be the reason is how I return the Cursors in those methods.
and if I understand it correctly closing the Cursor also closes the
database.
That does not sound quite right. You have to explicitly close the database after you've closed all cursors. The logcat errors are due to you not closing the databse and probably attempting to open another instance of it.
The order is important, cursors first, then the DB instance.
<bad joke in 3.. 2.. 1...>
The rest does not sound like any bad practice, when you gotta db it you just gotta db it. :D
[EDIT]: You said you've done this:
public Cursor getCoursesLeft()
{
// Open a readable database.
SQLiteDatabase database = this.getReadableDatabase();
^^^ here you're creating a new instance of the db
which means the db is opened for reading, and the scope of this variable
is lost outside this function. This means you can not close this instance explicitly
// Query the database and return the cursor.
return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}
Instead have a database variable that you can access outside this method and close it once you're done working with the Cursor (and you've closed the cursor)
SQLiteDatabase database;
public Cursor getCoursesLeft()
{
// Open a readable database.
database = this.getReadableDatabase();
// Query the database and return the cursor.
return database.query(DEGREE_PLAN_TABLE, null, DEGREE_COLUMN_TAKEN + " = ?",
new String[] { "0" }, null, null, DEGREE_COLUMN_CLASS_NAME + " COLLATE NOCASE");
}
public void someOtherFunction() {
Cursor blah = getCoursesLeft();
// do something with blah
blah.close();
database.close();
}
Not closing a cursor just causes memory leaks. Closing a database is different.
Closing a cursor is like closing a particular connection to certain .file files generated when the cursor is created.
Hence you should ALWAYS close your cursor.
Is this bad coding?
No, and yea. Don't let your Activity mess around with those temp files. While nothing will happen it just doesn't seem nice
I have created a database. And opened it :
public SQLiteDatabase open() {
String path = "/data/data/com.develop.assetcapture/databases/Asset_Directory";
db = SQLiteDatabase.openOrCreateDatabase(path, null);
return db;
}
I'm writing a user registration and what to enable them to reset their passwords.
I have no problem inserting new records or querying the database. However on my resetPassword(username,password) method I get an error message:
android.database.sqlite.DatabaseObjectNotClosedException:
Application did not close the cursor or database object that was opened here
Please help, I've been stuck on this for too long now.
When you query the database you usually receive a Cursor object. Here is an example:
public Cursor querySomething() {
final String whereClause = ...
final String[] params = ...
final Cursor c = this.getReadableDatabase().query(
Table.TABLE_NAME,
Table.allColumnNames(),
whereClause,
params, // parameters for where clause
null, // group
null, // having
null); // order
return c;
}
Using the cursor c you access the rows in the answer. When you have finished processing the answer you have to close the cursor object:
c.close();
So I'm trying to get the values from a SQLite database into a cursor, then pick a random value. I can read the cursor with getString() as I normally would in the method, but after it returns the cursor it doesn't work correctly. I don't know why..
Here's my method for getting the cursor from the database. It seems to work correctly.
public Cursor getRandomText(String Rating)
{
Cursor cursor = myDatabase.query("Elec0RandTexts", new String[] {"Message"}, "Rating=?",
new String[]{Rating}, null, null, null);
cursor.moveToFirst();
cursor.close();
return cursor;
}
Here's my code for reading the cursor after it's returned.
Cursor result = dbh.getRandomText(Rating);
result.moveToFirst();
int RandText = rand.nextInt(result.getCount());
result.moveToPosition(RandText);
Toast.makeText(getApplicationContext(), "" + result.getString(RandText), Toast.LENGTH_LONG).show();
result.close();
I'm probably making a stupid mistake and not realizing it, but I can't figure this out.
Thanks,
~Elec0
cursor.close(); // in getRandomText()
after that you cannot obtain any data from the cursor - it is closed. Remove this line.
You close() your Cursor before you return it. From where it is returned to, you are then attempting to call moveToFirst(). This cannot be done if the Cursor is closed.
In your getRandomText(String) method, you should return the meaningful data from your Cursor, rather than the Cursor object itself. That way, the method that created the Cursor can continue to close the Cursor as it should. (It should just happen at the end of the method)
I have a DB helper class that helps me insert and delete records of pieces of information in Android 1.6.
When I delete a record and insert a new one just after that, i get the following error
Ljava/lang/IllegalStateException;: Finalizing cursor android.database.sqlite.SQLiteCursor#43d63338 on t_forms that has not been deactivated or closed
I have gone through the web searching for an answer, and most forum posts say that a cursor is not closed.In fact the operations I am executing aren't really returning recordset data, so I am a little stumped on why logcat would throw this error...
So these are the 2 functions that get called one after the other..
//---deletes a particular form---
public boolean deleteForm(int formID)
{
return db.delete(DATABASE_TABLE, KEY_FORM_ID + "=" + formID, null) > 0;
}
//---insert a form into the database---
public long insertForm(int form_id, String lform_name, String lform_description, String sdcardPath)
{
ContentValues initialValues = new ContentValues();
initialValues.put(KEY_FORM_ID, form_id);
initialValues.put(KEY_FORM_NAME, lform_name);
initialValues.put(KEY_FORM_DESC, lform_description);
initialValues.put(KEY_SDCARDPATH, sdcardPath);
return db.insert(DATABASE_TABLE, null, initialValues);
}
What could be the problem?
The code you provided is not enough. But first close the cursor in onDestroy and onStop like this:
if(mCursor!= null && !mCursor.isClosed())
mCursor.close();
and then try calling startManagingCursor(cursor) after where you use your cursor object, if you use it to make a query, etc, call it after the operation you make with the cursor.