I understand that a after a database is closed, the cursor becomes "invalid", does that also close the cursor at the same time? Does that avoid having to do what is shown below?
example 1
public void String getResultsAndReturnString() {
String result = "";
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = qb.query(db, projection, null, null,
null, null, null);
cursor.close(); <-- explicit cursor close example one
db.close();
return result;
}
example 2
public void Cursor getResultsAndReturnCursor(){
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor cursor = qb.query(db, projection, null, null,
null, null, null);
return cursor;
}
public void closeOut(Cursor cursor, SQLiteDatabase dataBase){
cursor.close(); <-- explicit cursor close example two
dataBase.close();
}
The cursor isn't closed in the strict sense by closing the database (it's still there and you can perform operations on it), but as you know, closing the database makes the cursor useless. You should close cursors explicitly after you're done using them for a number of reasons:
1) As you noted, after closing the database, any remaining cursors become "invalid," and cannot be relied upon for accurate data;
2) You will see warnings in LogCat;
3) You risk memory leaks if you maintain a reference to a cursor; and
4) It's simply good programming practice to close out resources that you no longer need.
Related
Usually when I iterate over a cursor I use something like the following:
while (cursor.moveToNext()) {
// get stuff from the cursor
}
What's the best way to iterate an Android Cursor? has a nice discussion of the various options. But now I need to go backwards from last to first over the cursor.
So what can I do?
There are at least two options.
First, to specifically answer your question about iterating backwards over the cursor, you could do the following:
for (cursor.moveToLast(); !cursor.isBeforeFirst(); cursor.moveToPrevious()) {
// get stuff from the cursor
}
Second, you could populate the cursor in reverse order from sql and then iterate over the cursor in your normal way:
SQLiteDatabase db = myHelper.getWritableDatabase();
String[] columns = { MyDatabaseHelper.TEST_DATE, MyDatabaseHelper.SCORE };
String orderBy = MyDatabaseHelper.TEST_DATE + " DESC"; // This line reverses the order
Cursor cursor = db.query(MyDatabaseHelper.TESTS_TABLE_NAME, columns,
null, null, null, null, orderBy, null);
while (cursor.moveToNext()) {
// get stuff from the cursor
}
cursor.close();
db.close();
You can start the cursor in the last position, and use moveToPrevious() until you've finished.
cursor.moveToLast();
do
{
// Stuff
}
while (cursor.moveToPrevious());
I can't find what causing this error in my database, I posted some question before related to this issue but since the code is quite long i remove some of them that has the same
declaration because stackoverflow won't allow me to post more than 3000 characters. i tried using this method to close the cursor, but somehow it doesn't fix the problem.
public Cursor getMove(){
String[] columns = new String[]{KEY_ID1, KEY_MOVENAME};
Cursor c = null;
try {
c = ourDatabase.query(DATABASE_TABLE1, columns, null, null, null, null, null);
} finally {
if(c != null){
c.close();
}
}
return c;
}
Anyway [here's] the whole class I hope someone can help me.
Closing the cursor is the reason why I'm getting this error so instead of this:
public Cursor getMove(){
String[] columns = new String[]{KEY_ID1, KEY_MOVENAME};
Cursor c = null;
try {
c = ourDatabase.query(DATABASE_TABLE1, columns, null, null, null, null, null);
} finally {
if(c != null){
c.close();
}
}
return c;
}
I just used this line of code:
public Cursor getMove(){
String[] columns = new String[]{KEY_ID1, KEY_MOVENAME};
Cursor c = null;
c = ourDatabase.query(DATABASE_TABLE1, columns, null, null, null, null, null);
return c;
}
The reason may be that you are using multiple instances of your DB connections and not closing all cursors that you hand out. The answer that you accepted (your own) could be dangerous. Are you releasing the cursors that you hand out from this method ? You will end up taking precious resources on the phone that will never be released if you don't.
You can solve this by maintaining one database instance (by using a singleton to handle the DB connections) and closing all cursors eventually. Either marshal them into POJOs and close the cursors immediately or send back a cursor and manage it with a call to a method like activity.managedQuery(). You might also want to look at android's SQL lite locking mechanism.
My code is like below:
Cursor getResults() {
SQLiteDatabase db = dbHelper.getReadableDatabase();
Cursor c = qb.query(db, projection, null, null,
null, null, null);
db.close();
return c;
}
My question is, after db.close() is executed, is the cursor c still alive and navigable?
Thanks.
No. You do not want to use a cursor while the database is closed. When you call close(), it makes the object (and it's corresponding cursor) invalid.
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 one row database just for saving app data. My goal is to read one column (one value) from it.
This query returns all the columns in a Cursor:
public Cursor readAll() {
return getReadableDatabase().query(tableName, null, null, null, null, null, null);
}
It returns a Cursor with one row in it, just perfect. However, I don't want to read all columns at once, because it's slow as I have blob's in db too.
Instead, I'd like to read just one column at a time, separately. For example, for a column called "TEXT" it would be this:
public Cursor readText() {
String[] projection = new String[]{"TEXT"};
return getReadableDatabase().query(tableName, projection, null, null, null, null, null);
}
However, this won't work, as I get back a Cursor with zero rows.
So, how to read a specific column from SQLiteBatabase in Android?
public Cursor readText() {
return getReadableDatabase().rawQuery("SELECT colName FROM myTable", new String[] {});
}
Syntax seems to be correct. Check please that you use right name of the column. Showing the table generation code and actual query code could help.
You can use this one also
public Cursor readText() {
return getReadableDatabase().rawQuery("SELECT column_name FROM table_name", null);
}