Reputation: 15740
Here is the error:
02-08 16:35:00.899: ERROR/Database(468): android.database.sqlite.DatabaseObjectNotClosedException: Application did not close the cursor or database object that was opened here
Except, well, I am. Here is the method where this problem is occuring:
public static void getUpdates(String username, Context context) {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://10.0.2.2/tag/appgetfriendinfo.php");
try {
List<NameValuePair> nVPs = new ArrayList<NameValuePair>();
nVPs.add(new BasicNameValuePair("username", username));
httpPost.setEntity(new UrlEncodedFormEntity(nVPs));
HttpResponse response = httpClient.execute(httpPost);
ResponseHandler<String> rHandler = new BasicResponseHandler();
String result = rHandler.handleResponse(response);
JSONArray jArray = new JSONArray(result);
for(int i = 0; i < jArray.length(); i++) {
JSONObject jObj = jArray.getJSONObject(i);
String userCheck = jObj.getString("username");
TagDBAdapter dbHelper = new TagDBAdapter(context);
dbHelper.open();//OPENING THE DATABASE
Contact contact = new Contact();
String first = jObj.getString("firstname");
String last = jObj.getString("lastname");
String name = first + " " + last;
contact.setUsername(jObj.getString("username"));
contact.setFirstName(first);
contact.setLastName(last);
contact.setName(name);
contact.setPhoneNumber(jObj.getString("phonenumber"));
contact.setEmail(jObj.getString("email"));
contact.setHomePhone(jObj.getString("homephone"));
contact.setWorkPhone(jObj.getString("workphone"));
if(dbHelper.checkForExisting(userCheck) == true) {
dbHelper.createContact(contact);
}
else {
dbHelper.updateContactAuto(userCheck, contact);
}
dbHelper.close();//CLOSING THE DATABASE
}
} catch(ClientProtocolException e) {
Log.e("GETUPDATES", "CPE", e);
e.printStackTrace();
} catch(IOException e) {
Log.e("GETUPDATES", "IOE", e);
e.printStackTrace();
} catch(JSONException e) {
Log.e("GETUPDATES", "JSONE", e);
e.printStackTrace();
}
}
As you can see on the lines I noted in //comments, I am opening AND closing the database, yet I am still getting the error. Here is what is strange though, the error's source is in the SQLite's open() method.
ERROR/Database(468): at com.tagapp.android.TagDBAdapter.open(TagDBAdapter.java:62)
Which is this:
/**THESE ARE MY DBADAPTER'S OPEN AND CLOSE METHODS*/
public TagDBAdapter open() throws SQLException {
mDBHelper = new DatabaseHelper(m_context);
mDb = mDBHelper.getWritableDatabase();
return this;
}
public void close() {
mDBHelper.close();
}
These are straight from Google's notepad tutorial, and they have worked 100% for me in different instances. Does anyone have an idea of what is going on here? Thanks a lot.
Upvotes: 9
Views: 18503
Reputation: 9522
Looking this over as I am investigating a similar issue. One possibility I notice is that if you throw an exception in your loop for any reason, then even if you properly handle it, you drop out of the loop and the last open() never has a corresponding close. To fix this you'd want to put the close() statement in a finally{} block. Furthermore, I don't see any reason to create and open a new cursor for each iteration of the loop. Move that outside the loop so there's one and only one open() and the corresponding close() is the one in the finally block. (Alternatively you could have another try-catch construct inside the loop, so that the close() always gets run.)
Example:
public static void getUpdates(String username, Context context) {
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost("http://10.0.2.2/tag/appgetfriendinfo.php");
TagDBAdapter dbHelper; // DECLARE THIS HERE SO IT CAN BE ACCESSED OUTSIDE OF try BLOCK
try {
List<NameValuePair> nVPs = new ArrayList<NameValuePair>();
nVPs.add(new BasicNameValuePair("username", username));
httpPost.setEntity(new UrlEncodedFormEntity(nVPs));
HttpResponse response = httpClient.execute(httpPost);
ResponseHandler<String> rHandler = new BasicResponseHandler();
String result = rHandler.handleResponse(response);
JSONArray jArray = new JSONArray(result);
// MOVED TO OUTSIDE OF LOOP
dbHelper = new TagDBAdapter(context);
dbHelper.open();//OPENING THE DATABASE
for(int i = 0; i < jArray.length(); i++) {
JSONObject jObj = jArray.getJSONObject(i);
String userCheck = jObj.getString("username");
Contact contact = new Contact();
String first = jObj.getString("firstname");
String last = jObj.getString("lastname");
String name = first + " " + last;
contact.setUsername(jObj.getString("username"));
contact.setFirstName(first);
contact.setLastName(last);
contact.setName(name);
contact.setPhoneNumber(jObj.getString("phonenumber"));
contact.setEmail(jObj.getString("email"));
contact.setHomePhone(jObj.getString("homephone"));
contact.setWorkPhone(jObj.getString("workphone"));
if(dbHelper.checkForExisting(userCheck) == true) {
dbHelper.createContact(contact);
}
else {
dbHelper.updateContactAuto(userCheck, contact);
}
}
} catch(ClientProtocolException e) {
Log.e("GETUPDATES", "CPE", e);
e.printStackTrace();
} catch(IOException e) {
Log.e("GETUPDATES", "IOE", e);
e.printStackTrace();
} catch(JSONException e) {
Log.e("GETUPDATES", "JSONE", e);
e.printStackTrace();
} finally {
dbHelper.close();//CLOSING THE DATABASE
}
}
Upvotes: 0
Reputation: 77752
The problem is not the database object, it's the cursor - you have an open cursor lying around somewhere.
Make sure that all cursors are closed before you close the database. (Btw, if you want to be fancy, you can create a ContentProvider, use an SQLiteOpenHelper and not worry about closing it at all.)
Upvotes: 12