close() was not explicity called on database
I need to know where to call the db.close() in my code. I've added it on onCreate() method, but when I need to use some methods it says database not open, and then I've removed from onCreate() and it says close() was not explicity called. so where should I close, could it be inside each method of the class??
here is the code:
public class HoursPerDayDataHelper {
private static final String DATABASE_NAME = "database.db";
private static final int DATABASE_VERSION = 1;
protected static final String TABLE_NAME = "table";
protected String TAG = "HoursPerDayDataHelper";
private Context context;
private SQLiteDatabase db;
OpenHelper openHelper = null;
public HoursPerDayDataHelper(Context context) {
this.context = context;
openHelper = new OpenHelper(this.context);
this.db = openHelper.getWritableDatabase();
openHelper.onCreate(db);
}
public void close() {
if (openHelper != null) {
openHelper.close();
}
}
public void deleteAll() {
this.db.delete(TABLE_NAME, null, null);
}
public String selectDuration(String date) {
String duration = "";
Integer value = 0;
String returnment = "";
Log.i(TAG, "date do select: " + date);
Cursor cursor = this.db.query(TABLE_NAME, new String[] { "duration" },
"date = ? ", new String[]{ date }, null, null, null);
Log.i(TAG, "cursor string " + cursor);
if (cursor.moveToFirst()) {
do {
Log.i(TAG, "dentro do if cursor");
duration = cursor.getString(0);
value += Integer.parseInt(duration);
} while (cursor.moveToNext());
returnment = Integer.toString(value);
}else{
Log.i(TAG, "bla bla bla");
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
return returnment;
}
public ArrayList<String[]> selectTopContacts() {
ArrayList<String[]> list1 = new ArrayList<String[]>();
Cursor cursor = this.db.query(TABLE_NAME, null, null, null, null, null,
"duration desc");
if (cursor.moveToFirst()) {
do {
if (cursor.getString(2) != "") {
String[] data = new String[4];
data[0] = cursor.getString(2);
data[1] = cursor.getString(4);
data[2] = cursor.getString(5);
data[3] = cursor.getString(7);
list1.add(data);
} else {
String[] data = new String[3];
data[1] = cursor.getString(4);
data[2] = cursor.getString(5);
data[3] = cursor.getString(7);
list1.add(data);
}
} while (cursor.moveToNext());
}
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
return list1;
}
public static class OpenHelper extends SQLiteOpenHelper {
OpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS "
+ TABLE_NAME
+ "(id INTEGER PRIMARY KEY AUTOINCREMENT, duration TIME, date DATE, current_time TIME)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w("HoursPerDay Database",
"Upgrading database, this will drop tables and recreate.");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
}
And this is my Activity:
public class HoursPerDay extends Activity{
private String LOG_TAG = "HoursPerDay";
private TextView mDateDisplay;
public String date;
private int mYear;
private int mMonth;
private int mDay;
private int newDay;
private String hpdData;
private HoursPerDayDataHelper hpd;
OpenHelper openHelper = new OpenHelper(HoursPerDay.this);
static final int DATE_DIALOG_ID = 0;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.hours_per_day);
hpd = new HoursPerDayDataHelper(this);
// capture our View elements
mDateDisplay = (TextView) findViewById(R.id.dateDisplay);
// get the current date
final Calendar c = Calendar.getInstance();
mYear = c.get(Calendar.YEAR);
mMonth = c.get(Calendar.MONTH);
mDay = c.get(Calendar.DAY_OF_MONTH);
// display the current date (this method is below)
}
@Override
protected void onDestroy() {
super.onDestroy();
if (openHelper != null) {
openHelper.close();
}
if (hpd != null) {
hpd.close();
}
}
// the callback received when the user "sets" the date in the dialog
private DatePickerDialog.OnDateSetListener mDateSetListener = new DatePickerDialog.OnDateSetListener() {
public void onDateSet(DatePicker view, int year, int monthOfYear,
int dayOfMonth) {
mYear = year;
mMonth = monthOfYear;
mDay = dayOfMonth;
setBasicContent();
hpd.close();
}
};
protected Dialog onCreateDialog(int id) {
switch (id) {
case DATE_DIALOG_ID:
return new DatePickerDialog(this,
mDateSetListener,
mYear, mMonth, mDay);
}
return null;
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.layout.hoursperdaymenu, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
switch(item.ge开发者_如何学PythontItemId()){
case R.id.filter_by_day:
showDialog(DATE_DIALOG_ID);
return true;
case R.id.filter_by_user:
showDialog(DATE_DIALOG_ID);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
public void setBasicContent() {
date = (mMonth + 1) + "/" + newDay + "/" + mYear;
hpdData = this.hpd.selectDuration(date);
mDateDisplay.setText(hpdData);
hpd.close();
}
}
I think there are 2 ways:
- in
onPause
-method and check thereisFinishing
if yes -> close. Problem: if your app gets killed by app-killer, db remains open. - You open and close the DB each time (methods) you read/write.
EDIT:
Ok, I see why it could be caused. I think you misunderstood the usage of the SQLiteOpenHelper
. You never have to call the onCreate
-method.
Defently the better way is to make a DBHelper
class and use it in a separate calls, lets say SQLDataHandler
.
Your activity look good. I changed a few things, look if it helps. I'll mark them:
That's all what should be in the Helper class:
public static class OpenHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "database.db";
private static final int DATABASE_VERSION = 1;
protected static final String TABLE_NAME = "table";
protected String TAG = "HoursPerDayDataHelper";
Just leave it CREATE TABLE
it gets only created/called if there isn't one existing.
I have seen errors occurring if the String is passed directly
@Override
public void onCreate(SQLiteDatabase db) {
String query = "CREATE TABLE "
+ TABLE_NAME
+ "(id INTEGER PRIMARY KEY AUTOINCREMENT, duration TIME, date DATE, current_time TIME)";
db.execSQL(query);
}
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
OpenHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
}
To use it:
Just call in your DataHandler
class :
OpenHelper helper = new OpenHelper(ctx);
// SQLiteDatabase db = helper.getReadableDatabase();
SQLiteDatabase db = helper.getWritableDatabase();
All other stuff, like deleting, adding and so on, should be done in a "DataHandler" class.
Just use the same two methods there to get your DB. At the end, when you are finished, you call just in you DataHandler
class db.close()
.
Like this the activity itself never uses de DB directly. Better practice I think ;)
I hope it helps. For any other questions, just ask :)
EDIT2:
First, in general it should work with a inner class.
BUT: In case you want to add another table from another class it won't work anymore. Thats why it's the better way to put it in a separate class from beginning. It's even reusable (with some smal adjustments).
Put the code I posted in your class OpenHelper. Nothing more.
Then, put the data manipulation stuff in a class called something like: DataHandlerDB.
Code example:
package ...;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class DataHandlerDB {
public static void persistAll(Context ctx, List<Module> moduleList) {
DatabaseHelper helper = new DatabaseHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values = new ContentValues();
for (Module m : moduleList) {
values.put("_id", m.get_id());
values.put("name", m.getModule());
db.insert("module", null, values);
}
db.close();
}
public static List<Module> findAll(Context ctx) {
List<Module> result = new ArrayList<Module>();
DatabaseHelper helper = new DatabaseHelper(ctx);
SQLiteDatabase db = helper.getReadableDatabase();
Cursor c = db.query(ModuleDB.TABLE_NAME, new String[] { ModuleDB.ID,
ModuleDB.MODULE}, null, null, null, null, null);
while (c.moveToNext()) {
Module m = new Module(c.getInt(0), c.getString(1));
result.add(m);
}
c.close();
db.close();
return result;
}
// Update Database entry
public static void update(Context ctx, Module m) {
DatabaseHelper helper = new DatabaseHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("_id", m.get_id());
values.put("name", m.getModule());
db.update("module", values, null, null);
db.close();
}
public static void delete(Context ctx, Module m) {
DatabaseHelper helper = new DatabaseHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("_id", m.get_id());
values.put("name", m.getModule());
db.delete("module","_id = m.get_id()", null);
db.close();
}
public static void createDB(Context ctx) {
DatabaseHelper helper = new DatabaseHelper(ctx);
SQLiteDatabase db = helper.getWritableDatabase();
db.close();
}
}
In order to be more efficient the methods are static
, you won't need to create objects.
Use it like this: In your activity
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get the a writable DB, in case it's not existing it gets created.
DataHandlerDB.createDB(this);
// get stuff out of DB
moduleList = DataHandlerDB.findAll(this);
adapter = new ArrayAdapter<Module>(this,
android.R.layout.simple_list_item_1, moduleList);
setListAdapter(adapter);
}
if you open in onCreate, then close in onDestroy
精彩评论