开发者

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 there isFinishing 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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜