I'm looking through the NotePad example that comes with the Android SDK and I was wondering if someone could clarify why the the variable db is never closed in the update function? It's usually a good idea to close the database when it is no longer in use to prevent leaks. Ideas?
#Override
public int update(Uri uri, ContentValues values, String where, String[] whereArgs) {
// Opens the database object in "write" mode.
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
... // More code, db.close() is never called?!
// Returns the number of rows updated.
return count;
}
Related
I am having a big problem with my database. When I try to make the first call to the database since the app launches, I get a crash saying:
attempt to re-open an already-closed object: SQLiteDatabase /data/user/0/<path_to_db>
I am using a DBHelper class which extends SQLiteOpenHelper.
When I launch the app the first time, it should create the DB etc, and then have an empty DB which should still allow me to do some queries on it.
However, when I do my first query, it crashes with the above error.
Here's the query:
public TerminalList getTerminalLocations() {
SQLiteDatabase db = getReadableDatabase();
Cursor cursor = db.query(LOCATION_TABLE_NAME, null, null, null, null, null, null);
//do stuff
cursor.close();
db.close();
return locationList;
}
Its crashing on the first line!!
SQLiteDatabase db = getReadableDatabase();
It doesn't even get as far as the cursor!
How is this possible? Does anyone know how to fix this?
Does it make a difference that this is being called from the OnCreateView of my fragment? Here is how I call it. Its pretty standard:
private void getLocations() {
DBHelper db = DBHelper.getInstance(getActivity());
TerminalList locations = db.getTerminalLocations();
//do stuff
}
I've tried commenting out this call, but it pushes the problem to the next DB call, so is happening with every single DB call in the app!!
Thanks.
Try something like this for the utility method:
public Cursor getWhatyouNeed(SQLiteDatabase db, params...) {
Cursor yourData = db.query(your_query_params...);
// your logic
return yourData;
}
I have a listview activity which populates data through an sqlite database; however, whenever I enter onPause and then go into onResume my app crashes and I receive this error: "java.lang.IllegalStateException: trying to requery an already closed cursor android.database.sqlite.SQLiteCursor#418106a8". Would anyone know how to stop this? Is there a method I have to call in onPause?
#Override
protected void onResume() {
super.onResume();
uGraduateListAdapter = new ArrayAdapter<String>(ListOfAlarms.this, android.R.layout.simple_list_item_1, populateList());
listOfAlarms.setAdapter(uGraduateListAdapter);
Log.i(TAG, "Resume was called");
}
#Override
protected void onPause() {
super.onPause();
Log.i(TAG, "Pause was called");
sqliteDatabase.close();
}
public List<String> populateList(){
// We have to return a List which contains only String values. Lets create a List first
List<String> uGraduateNamesList = new ArrayList<String>();
// First we need to make contact with the database we have created using the DbHelper class
AndroidOpenDbHelper openHelperClass = new AndroidOpenDbHelper(this);
// Then we need to get a readable database
sqliteDatabase = openHelperClass.getReadableDatabase();
// We need a a guy to read the database query. Cursor interface will do it for us
//(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
cursor = sqliteDatabase.query(AndroidOpenDbHelper.TABLE_NAME_ALARM, null, null, null, null, null, null);
// Above given query, read all the columns and fields of the table
startManagingCursor(cursor);
// Cursor object read all the fields. So we make sure to check it will not miss any by looping through a while loop
while (cursor.moveToNext()) {
// In one loop, cursor read one undergraduate all details
// Assume, we also need to see all the details of each and every undergraduate
// What we have to do is in each loop, read all the values, pass them to the POJO class
//and create a ArrayList of undergraduates
String alarmName = cursor.getString(cursor.getColumnIndex(AndroidOpenDbHelper.COLUMN_NAME_ALARM_NAME));
// String ugUniId = cursor.getString(cursor.getColumnIndex(AndroidOpenDbHelper.COLUMN_NAME_UNDERGRADUATE_UNI_ID));
String alarmTotalTime = cursor.getString(cursor.getColumnIndex(AndroidOpenDbHelper.COLLUMN_ALARM_TOTALTIME));
// Finish reading one raw, now we have to pass them to the POJO
TestAlarm ugPojoClass = new TestAlarm();
ugPojoClass.setTitle(alarmName);
ugPojoClass.setTotalTime(alarmTotalTime);
// Lets pass that POJO to our ArrayList which contains undergraduates as type
pojoArrayList.add(ugPojoClass);
// But we need a List of String to display in the ListView also.
//That is why we create "uGraduateNamesList"
uGraduateNamesList.add(alarmName);
}
// If you don't close the database, you will get an error
sqliteDatabase.close();
return uGraduateNamesList;
}
You are using deprecated methods (startManagingCursor()), which is dangerous.
How I see what happens: when you close your database (twice actually: in populateList() and onPause()), your cursors to this database become invalid. But since you called startManagingCursor(), your Activity retains your cursors and tries to call requery() on them when restarting, which throws the error.
Try not calling startManagingCursor() at all, just cursor.close() when you're done with it. Or you can migrate to newer LoaderManager altogether.
in my case, I use ContentProvider together with CursorAdapter, the content provider has the methods to query, and bulkInsert. if the bulkInsert runs before query method, I get the exception:
java.lang.IllegalStateException: database /data/data/com.example/databases/testdb (conn#0) already closed
I think this is because in the bulkInsert method:
public int bulkInsert(Uri uri, ContentValues[] insertValuesArray) {
switch (sUriMatcher.match(uri)) {
case ROUTE_ENTRIES:
SQLiteDatabase localSQLiteDatabase = mDatabaseHelper.getWritableDatabase();
localSQLiteDatabase.beginTransaction();
localSQLiteDatabase.setTransactionSuccessful();
// do the work
// Ends the transaction and closes the current db instances
localSQLiteDatabase.endTransaction();
localSQLiteDatabase.close();
}
}
as you can see, localSQLiteDatabase.close() is called in the bulkInsert method. I did this as I followed the threadsample from google. Link: https://code.google.com/p/android-source-browsing/source/browse/samples/training/threadsample/src/com/example/android/threadsample/DataProvider.java?repo=platform--development&name=tools_r22&r=2c063c889aa816e0de91bf17fdc0c78f48d5e2d0
can anyone suggest if I should close the database in the bulkInsert or not? if I don't close, is there any leak?
thanks a lot!
cheers,
Martin
I'm using SQLIte loader (cwac-loaderex). i'm performing set of operation in a background thread. the operation includes inserting new record, updating the existing one as well as deleting the record.
These operations i'm performing on cursor object like this. these methods are present in loader class & i'm accessing these from my background thread.
#Override
public void Insert(String table, String nullColumnHack,
ContentValues values) {
mLoader.insert(table, nullColumnHack, values);
}
#Override
public void Update(String table, ContentValues values,
String whereclause, String[] whereargs) {
// TODO Auto-generated method stub
mLoader.update(table, values, whereclause, whereargs);
}
In few scenarios like. Once i insert record, i need the primary key to update another record. i'm failing to get those. Once thread completes its execution the UI will get updated and i'm able to access the required value onPostexecute method. But i want the values soon after i insert to Database.
As per i know, that to reflect the updated values i'm calling the insert, update & delete method directly on Loader object.
How to access the inserted row, in the same thread soon after insert is called?
When you call .close() on a Cursor Object, does it mean that for the rest of the Activity's duration it cannot be used? The following is a method within my Manager Object:
Cursor cursor = null;
try {
SQLiteDatabase db = openDb();
cursor = db.query("table", null, "id=?", new String[] { id }, null, null, null);
cursor.moveToFirst();
long dateTime = cursor.getLong(1);
cursor.close();
return dateTime ;
} catch (CursorIndexOutOfBoundsException e) {
return -1;
} finally {
if (cursor != null) {
cursor.close();
}
closeDb();
}
This is the method that's throwing me an IllegalStateException. However, there's a slight twist: it only throws an error the second time it is called. Tracing the stacktrace, I find that the line causing me trouble is the following:
Cursor cursor = db.query("table", null, "id=?", new String[] { id }, null, null, null);
Just to clear things up a bit, this method can be called several times within the Activity's lifetime through clicking of a particular ListView item. The openDb() and closeDb() methods are as follows:
public SQLiteDatabase openDb() {
if (mDbHelper == null) {
mDbHelper = new DatabaseHelper(mContext);
}
return mDbHelper.getWritableDatabase();
}
public void closeDb() {
mDbHelper.close();
}
And these are stored in the superclass of my Manager object. mDbHelper is a static Object.
Being fairly new to Android programming, I'm wondering why this would throw me an exception. The only logical explanation I can think of is that Cursor Objects are actually re-used, and they should not be closed for the duration of an activity. Am I right? And if I am, when do you actually close the Cursor?
---EDIT---
Having tinkered around with the code a bit, I seem to be getting the exception being thrown on a much more irregular basis. For some odd reason, it seems to happen randomly; I can click on eight multiple ListView items with no issues, and suddenly bam! The ninth causes the application to crash.
Because clicking on a ListView also invokes a method which updates that very same table (which up till now has caused me no problems thus far), I think it's only relevant that I include that as well:
try {
SQLiteDatabase db = openDb();
ContentValues cv = new ContentValues();
cv.put("id", id);
cv.put("dateTime", dateTime);
long affected = db.replace("table", null, cv);
return affected;
} finally {
closeDb();
}
As you can see, no rocket science is involved here. However, this method has now started to throw similar Exceptions, happening on the line:
long affected = db.replace("table", null, cv);
I'm starting to suspect that it's a click-too-fast problem, and the SQLite connections are not given enough time to close. Because there is no pattern to the crashes that I can discern; sometimes it crashes on the third try, sometimes on the eighth, sometimes it even seems to work fine till well past the tenth.
Could that be possible?
As the docs say after you have called close() your Cursor becomes forever invalid.
Also, there's no need to call close 2 times in your function. It's enough to call it in the finally block only
Because you call the close() method on the static object, it may not necessarily "nullify" the static object. So when you check if mDbHelper is null in the openDb() method the second time, it will pass this condition, and therefore the method will unintentionally return a closed database. When you try and query this closed database, it will therefore throw the illegalstateexception.
Try:
public SQLiteDatabase closeDb() {
mDbHelper.close()
mDbHelper = null;
}
I hope I have helped.