Android SQLite不使用SQLiteOpenHelper创建表

时间:2011-08-23 11:30:56

标签: android sqlite

我已将此问题发布到android-developer邮件列表中,但没有任何成功。所以我们试试吧:))

我想在这里实现的目标非常简单。使用SQLiteOpenHelper的子类我试图创建一个新的新数据库,如果它不存在所以我依赖于该类暴露的onCreate() - 方法。 这是我的代码:

public class CurrencyStorageHelper extends SQLiteOpenHelper {

private static final String TAG = "CurrencyStorageHelper";
private static final int DATABASE_VERSION = 1;

public static final String DATABASE_NAME = "easycurrencyconverter.db";
public static final String COL_ID = "_id";

public static final String COL_CURRENCY_CODE = "currency_code";
public static final String COL_CURRENCY_VALUE = "currency_value";
public static final String COL_LAST_UPDATE = "last_update";
public static final String COL_LAST_DOWNLOADED = "last_downloaded";
public static final String COL_IS_TARGET_CURRENCY = "is_target_currency";
public static final String COL_CURRENCY_POSITION = "position";

public static final String TABLE_DEFAULT_CURRENCIES = "defaultcurrencies";
public static final String TABLE_CURRENCIES = "currencyhistory";
public static final String TABLE_CURRENCY_DEFINITION = "currencydefinition";

public static final String COL_DEFINITION_CODE = "code";
public static final String COL_DEFINITION_FULL_NAME = "full_name";




private static final String DATABASE_CREATE_1 = 
            "CREATE TABLE " + TABLE_CURRENCIES + " (" + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT " +
                                   ", " + COL_CURRENCY_CODE + " TEXT NOT NULL" +
                                   ", " + COL_CURRENCY_VALUE + " REAL NOT NULL" +
                                   ", " + COL_LAST_UPDATE + " REAL NOT NULL" +
                                   ", " + COL_LAST_DOWNLOADED + " REAL NOT NULL); ";
private static final String DATABASE_CREATE_2 = 
            "CREATE TABLE " + TABLE_DEFAULT_CURRENCIES + " (" + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT " +
                                   ", " + COL_CURRENCY_CODE + " TEXT NOT NULL" +
                                   ", " + COL_CURRENCY_VALUE + " REAL NOT NULL" +
                                   ", " + COL_CURRENCY_POSITION + " INTEGER NOT NULL" +
                                   ", " + COL_LAST_UPDATE + " REAL NOT NULL" +
                                   ", " + COL_LAST_DOWNLOADED + " REAL NOT NULL" + 
                                   ", " + COL_IS_TARGET_CURRENCY + " NUMERIC ); ";
private static final String DATABASE_CREATE_3 =
            "CREATE TABLE " + TABLE_CURRENCY_DEFINITION + " (" + COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT " +
                                   ", " + COL_DEFINITION_CODE + " TEXT NOT NULL" +
                                   ", " + COL_DEFINITION_FULL_NAME + " TEXT NOT NULL); ";


private static final String DATABASE_DROP = "DROP TABLE IF EXISTS " + TABLE_CURRENCIES + "; " +
                                            "DROP TABLE IF EXISTS " + TABLE_DEFAULT_CURRENCIES + ";" + 
                                            "DROP TABLE IF EXISTS " + TABLE_CURRENCY_DEFINITION + ";";

public CurrencyStorageHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);

}

@Override
public void onOpen(SQLiteDatabase db) {
    super.onOpen(db);
    Log.d(TAG, "Opening the database... " + db.getPath() + " version " + db.getVersion());
    db.setLockingEnabled(true);
} 


@Override
public void onCreate(SQLiteDatabase database) {

    if (database.isDbLockedByCurrentThread()){
        Log.d(TAG, "Database locked by current thread...");
    }


    if (database.isDbLockedByOtherThreads()){
        Log.e(TAG, "Database locked by OTHER thread...");
    }

    if (database.isOpen()){
        Log.d(TAG, "OK.. Database open");
    }

    if (database.isReadOnly()){
        Log.e(TAG, "The database is read only");
    }

    if (database.inTransaction()){
        Log.e(TAG, "Why id the databse in transaction???");
    }

    Log.d(TAG, "Call to onCreate");

    Log.d(TAG, "Creating table..." + DATABASE_CREATE_1);

    database.beginTransaction();
    database.execSQL(DATABASE_CREATE_1);
    database.endTransaction();

    Log.d(TAG, "Creating table..." + DATABASE_CREATE_2);
    database.beginTransaction();
    database.execSQL(DATABASE_CREATE_2);
    database.endTransaction();

    Log.d(TAG, "Creating table..." + DATABASE_CREATE_3);        
    database.beginTransaction();
    database.execSQL(DATABASE_CREATE_3);
    database.endTransaction();
    insertInitialCurrencies(database);
}

/**
 * Create the default values to be shown to the user main activity when the application
 * is ran for the first time and no currencies have been downloaded yet.
 * @param database
 */
private void insertInitialCurrencies(SQLiteDatabase database){

    int i = 1;
    //TODO The fact that USD is the target currency is arbitrary. Maybe we should read user's
    //locale to get her currency
    insertDefaultCurrency(database, "USD", "U.S. Dollar", 1, i++, true, (new Date()).getTime(), (new Date()).getTime(), true, false);
    insertDefaultCurrency(database, "EUR", "Euro", 1, i++, false, (new Date()).getTime(), (new Date()).getTime(), false, false);
    insertDefaultCurrency(database, "GBP", "British Pound", 1, i++, false, (new Date()).getTime(), (new Date()).getTime(), false, false);
    insertDefaultCurrency(database, "JPY", "Japanese Yen", 1, i++, false, (new Date()).getTime(), (new Date()).getTime(), false, false);
    insertDefaultCurrency(database, "CNY", "Chinese Yuan", 1, i++, false, (new Date()).getTime(), (new Date()).getTime(), false, false);
    insertDefaultCurrency(database, "CHF", "Swiss Franc", 1, i++, false, (new Date()).getTime(), (new Date()).getTime(), false, true);


}


    /**
 * Insert a new currency value which will be shown on the user main activity.
 * 
 */
private void insertDefaultCurrency(SQLiteDatabase database, 
                            String currencyCode, 
                            String currencyFullName, 
                            double value, 
                            int position,
                            boolean isTargetCurrency,
                            long lastModifiedDate,
                            long lastDownloadedDate,
                            boolean startTransaction,
                            boolean endTransaction){
    ContentValues vals = new ContentValues();
    vals.put(COL_CURRENCY_CODE, currencyCode);
    vals.put(COL_CURRENCY_VALUE, value);
    vals.put(COL_LAST_DOWNLOADED, lastDownloadedDate);
    vals.put(COL_LAST_UPDATE, lastModifiedDate);
    vals.put(COL_IS_TARGET_CURRENCY, (isTargetCurrency? 1 : 0));
    vals.put(COL_CURRENCY_POSITION, position);

    if (startTransaction){
        database.beginTransaction();
    }
    Log.d(TAG, "Adding default currency..." + currencyCode);
    database.insertOrThrow(TABLE_DEFAULT_CURRENCIES, null, vals);

    if (endTransaction){
        database.endTransaction();
    }
}

这里发生的事情是: 实际创建了db文件(调整大小为3072字节),但是没有创建表,所以当我午餐时查询数据库时我得到了异常

android.database.sqlite.SQLiteException: no such table.

但是我没有得到任何SQL异常,因此我不知道为什么不创建表。

此外,每次运行我的应用程序时都会执行onCreate() - 方法。如果DB不存在,它应该只执行一次吗?为什么一直这么叫?

调试应用程序我注意到打开数据库之后:

  1. getVersion()返回0
  2. isInTransaction()返回true
  3. SQLiteDatabase - 实例具有私有属性mStackTrace 设置为DatabaseObjectNotClosedException,但我没有光标 开了。
  4. 这一切都发生在模拟器和我的手机(三星Galaxy S2)上,所以我在这里缺少一些东西。

    感谢您提供给我的任何帮助/线索!!

4 个答案:

答案 0 :(得分:2)

您缺少setTransactionSuccessful()调用。请遵循以下模式:

   db.beginTransaction();
   try {
     ...
     db.setTransactionSuccessful();
   } finally {
     db.endTransaction();
   }

答案 1 :(得分:1)

显然它现在正在运作。我放了一个“COMMIT;”在最后一个CREATE TABLE之后。 我不确定为什么我需要强制提交,但这最终让我的代码工作。 但是看着日志我得到了一个非阻塞异常:

08-23 15:45:17.714: ERROR/Database(18195): Failure 1 (cannot rollback - no transaction is active) on 0x1a3558 when executing 'ROLLBACK;'

但是现在还没有阻止我的代码被执行。

谢谢大家!!

尼科

答案 2 :(得分:0)

卸载您的应用程序并重新安装。

答案 3 :(得分:0)

看看openOrCreateDatabase方法。这可能更有意义覆盖,只是挂在它创建的代码部分。

http://developer.android.com/reference/android/database/sqlite/SQLiteDatabase.html