为什么我的构造函数没有被调用



我正试图向SQLite表添加一些记录,但LogCat告诉我该表不存在。DDMS显示,是的,该表没有被创建。

然而,我确实在SQLiteOpenHelper类中创建了表:

public class SQLiteHandlerDeliveryItem extends SQLiteOpenHelper {
    . . .
    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        String CREATE_DELIVERYITEMS_TABLE = "CREATE TABLE " +
                TABLE_DELIVERYITEMS + "("
                + COLUMN_ID + " INTEGER PRIMARY KEY," + COLUMN_INVOICENUM + " TEXT,"
                + COLUMN_UPCPLU + " TEXT," + COLUMN_VENDORITEMID + " TEXT,"
                + COLUMN_PACKSIZE + " INTEGER," + COLUMN_DESCRIPTION + " TEXT,"
                //+ COLUMN_COST + " REAL,"  + COLUMN_MARGIN + " REAL," + COLUMN_LISTPRICE + " REAL,"
                + COLUMN_COST + " REAL DEFAULT 0,"  + COLUMN_MARGIN + " REAL DEFAULT 0," + 
COLUMN_LISTPRICE + " REAL DEFAULT 0,"
                + COLUMN_DEPTNUM + " INTEGER," + COLUMN_SUBDEPT + " TEXT," + COLUMN_QTY + " TEXT"
                + ")";
        sqLiteDatabase.execSQL(CREATE_DELIVERYITEMS_TABLE);
    }

我调用类的添加记录的方法:

SQLiteHandlerDeliveryItem sqliteHandler = new SQLiteHandlerDeliveryItem(SQLiteActivity.this, null);
sqliteHandler.addDeliveryItem(delItem);

这应该调用SQLiteHandlerDelveryItem的构造函数(当sqliteHandler被实例化时),但它没有!我在onCreate()方法中得到了一个断点,当然,它从未到达。

为什么?如何强制调用构造函数,从而创建表?

奇怪的是,我还在另一个(正在工作的)SQLiteOpenHelper类中放置了一个断点,而且它未到达。。。什么它至少工作过一次,因为表确实存在/是根据该代码创建的。

所以很明显,我的挥杆在某个地方有一个洞;我误解了什么或做错了什么?

更新

我过早地将答案标记为答案。

关于:

"1.您必须在某个时刻调用getWritableDatabase()或getReadableDatabase()。"

在每个创建或读取记录的方法中,我都会调用getWritableDatabase(),如下所示:

public long addDeliveryItem(DeliveryItem delItem) {
    long IdAdded = 0;
    ContentValues values = new ContentValues();
    values.put(COLUMN_INVOICENUM, delItem.get_invoiceNumber());
    . . .
    values.put(COLUMN_QTY, delItem.get_quantity());
    SQLiteDatabase db = this.getWritableDatabase(); <= Rot Cheer
    if (db != null) {
        IdAdded = db.insert(TABLE_DELIVERYITEMS, null, values);
    }
    . . .

关于:

"2.在SQLiteHandlerDelveryItem的构造函数中,必须调用super(…)。"

在扩展SQLiteOpenHelper:的类中调用super

public SQLiteHandlerDeliveryItem(Context context, SQLiteDatabase.CursorFactory factory)     
{
    super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}

所以。。。我仍然不知道问题/解决方案是什么…

更新2

因此,当我试图在LogCat中将一条记录插入该表时,我看到的是:

E/SQLiteLog﹕(1) 没有这样的表:deliveryitems

然而,我尝试添加记录的代码实例化了相应的/适当的类,该类扩展了SQLiteOpenHelper,如下所示:

else if ("Delivery Items".equals(tableName)) {
    try {
        JSONArray jsonArr = new JSONArray(result);
        for (int i = 0; i < jsonArr.length(); i++) {
            JSONObject jsonObj = jsonArr.getJSONObject(i);
            String invNum = jsonObj.getString("invoiceNumber");
        . . .                        
        // Prepare for writing to db
        DeliveryItem delItem = new DeliveryItem();
        delItem.set_invoiceNumber(invNum);
        . . .                        
        SQLiteHandlerDeliveryItem sqliteHandler = new  
            SQLiteHandlerDeliveryItem(SQLiteActivity.this, null);
        sqliteHandler.addDeliveryItem(delItem);
    }
}

并且该类具有创建表的代码:

public class SQLiteHandlerDeliveryItem extends SQLiteOpenHelper {
        . . .
public SQLiteHandlerDeliveryItem(Context context, SQLiteDatabase.CursorFactory factory)   
{
    super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
    String CREATE_DELIVERYITEMS_TABLE = "CREATE TABLE " +
            TABLE_DELIVERYITEMS + "("
            + COLUMN_ID + " INTEGER PRIMARY KEY," + COLUMN_INVOICENUM + " TEXT,"
            + COLUMN_UPCPLU + " TEXT," + COLUMN_VENDORITEMID + " TEXT,"
            + COLUMN_PACKSIZE + " INTEGER," + COLUMN_DESCRIPTION + " TEXT,"
            + COLUMN_COST + " INTEGER,"  + COLUMN_MARGIN + " INTEGER," + COLUMN_LISTPRICE + " INTEGER,"
            + COLUMN_DEPTNUM + " INTEGER," + COLUMN_SUBDEPT + " TEXT," + COLUMN_QTY + " TEXT"
            + ")";
    sqLiteDatabase.execSQL(CREATE_DELIVERYITEMS_TABLE);
}

所以。。。我做错了什么,还是没做对?

更新3

确实没有创建表。LogCat中的错误消息表明情况确实如此(它是"没有这样的表:deliverytitems")。

我的构造函数是这样的:

@Override
public void onCreate(SQLiteDatabase db) {
    String CREATE_DELIVERYITEMS_TABLE = "CREATE TABLE " +
            TABLE_DELIVERYITEMS + "("
            + COLUMN_ID + " INTEGER PRIMARY KEY," + COLUMN_INVOICENUM + " TEXT,"
            + COLUMN_UPCPLU + " TEXT," + COLUMN_VENDORITEMID + " TEXT,"
            + COLUMN_PACKSIZE + " INTEGER," + COLUMN_DESCRIPTION + " TEXT,"
            + COLUMN_COST + " INTEGER,"  + COLUMN_MARGIN + " INTEGER," + COLUMN_LISTPRICE + " INTEGER,"
            + COLUMN_DEPTNUM + " INTEGER," + COLUMN_SUBDEPT + " TEXT," + COLUMN_QTY + " TEXT"
            + ")";
    db.execSQL(CREATE_DELIVERYITEMS_TABLE);
}

实际上,这个代码并没有被输入。那么,我必须跳过什么环才能调用构造函数呢?

我想当我实例化类时会发生这种情况:

SQLiteHandlerDeliveryItem sqliteHandler = new 
    SQLiteHandlerDeliveryItem(SQLiteActivity.this, null);

即使在调用它的时候,构造函数如何知道arg(SQLiteDatabasedb)是什么——它从哪里得到这个值?

我确实有一个数据库,只有一张表。它只是拒绝添加第二个表。

正如某个地方推荐的那样,我添加了一个单独的类,为我想添加到数据库中的每个表扩展SQLiteOpenHelper。

当我到达那条线时:

SQLiteHandlerDeliveryItem sqliteHandler = new 
    SQLiteHandlerDeliveryItem(SQLiteActivity.this, null);

并将F7进行混合,然后进入类构造函数:

public SQLiteHandlerDeliveryItem(Context context, SQLiteDatabase.CursorFactory factory)  
{
    super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}

但不是onCreate事件。

所以"难怪"我没有deliveryitems表,因为创建所述表的代码永远无法到达;但为什么它没有被触及——我必须做什么才能让它被触及?

  1. 您必须在某个时刻调用getWritableDatabase()getReadableDatabase()

  2. SQLiteHandlerDeliveryItem的构造函数中,必须调用super(…).

首先,方法SQLiteOpenHelper.onCreate()不是构造函数。我不确定,但看起来你把问题中的两个概念混淆了。


现在开始努力解决问题。。。

您的表似乎没有被创建。来自SQLiteOpenHelper.onCreate():的联机帮助

public abstract void onCreate (SQLiteDatabase db)
Called when the database is created for the first time. This is where the creation of tables and the initial population of the tables should happen.

因此,对于典型的用例,这个方法只会被调用一次——当应用程序第一次安装时(第一次使用数据库)。此时,将调用onCreate()来创建实际的表。但这并不是每次运行应用程序时都调用的。

我的建议是检查是否存在问题-卸载应用程序,然后重试。在这个方法中放置一个断点,以确保它确实运行了。

有时可能发生的情况是,我们在应用程序上有一个数据库,然后更新内容以添加表,然后忘记卸载。另一种正确的方法是使用onUpgrade()方法添加新表。

让我知道结果如何,或者我是否误解了这个问题。

正如我所希望的,它实际上是一个简单的修复方法:只需增加数据库版本的值。我在奥的"Android编程"第262页上读到了这篇文章:

数据库版本…如果计算机上的数据库版本低于database_version,系统将运行onUpgrade方法将数据库升级到当前级别

因此,你所需要做的就是增加这个数字:

    private static final int DATABASE_VERSION = 2; 
    // I changed it from "1" to "2", but you could change it to anything you want, I reckon (42, or 1776, or whatever).

增加版本值会导致onUpgrade运行,它会删除数据库的旧版本,然后调用onCreate:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_DELIVERYITEMS);
    onCreate(db);
}

onCreate()事件会执行此操作—添加DDL以创建表。

以下是在上下文中扩展SQLiteOpenHelper的类中的相关代码:

public class SQLiteHandlerDeliveryItem extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2; 
private static final String DATABASE_NAME = "HHS.db";
private static final String TABLE_DELIVERYITEMS = "deliveryitems";
private static final String COLUMN_ID = "_id";
. . .
private static final String COLUMN_QTY = "quantity";
public SQLiteHandlerDeliveryItem(Context context, SQLiteDatabase.CursorFactory factory)  
{
    super(context, DATABASE_NAME, factory, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
    String CREATE_DELIVERYITEMS_TABLE = "CREATE TABLE " +
            TABLE_DELIVERYITEMS + "("
            + COLUMN_ID + " INTEGER PRIMARY KEY," + COLUMN_INVOICENUM + " TEXT,"
. . .
            + COLUMN_DEPTNUM + " INTEGER," + COLUMN_SUBDEPT + " TEXT," + COLUMN_QTY + " 
TEXT"
            + ")";
    db.execSQL(CREATE_DELIVERYITEMS_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    db.execSQL("DROP TABLE IF EXISTS " + TABLE_DELIVERYITEMS);
    onCreate(db);
}
. . .

因此,在我看来,拥有多个扩展SQLiteOpenHelper的类是一件好事,因为这样你就可以将代码分开,而不是拥有一对巨大的onUpgrade/onCreate意大利面条。

最新更新