Android SQLite не создает таблицы с использованием SQLiteOpenHelper - PullRequest
0 голосов
/ 23 августа 2011

Я оставил этот вопрос в списке рассылки 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();
    }
}

Здесь происходит следующее: файл БД фактически создается (размер 3072 байта), но таблицы не создаются, поэтому, когда я запускаю метод для запроса БД, я получаю исключение

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

Однако я не получаю никаких исключений SQL, поэтому понятия не имею, почему таблицы не создаются.

Кроме того, onCreate() -метод выполняется каждый раз, когда язапустил мое приложение.Должно ли это выполняться только один раз, когда БД не существует?Почему он все время вызывается?

Отладка приложения Я заметил, что после открытия БД:

  1. getVersion() возвращает 0
  2. isInTransaction() возвращает true
  3. У экземпляра SQLiteDatabase есть закрытый атрибут mStackTrace, установленный на DatabaseObjectNotClosedException, но у меня еще нет открытого курсора.

Все это происходитс эмулятором, а также с моим мобильным телефоном (Samsung Galaxy S2), поэтому мне здесь чего-то не хватает.

Спасибо за любую помощь / подсказку, которую вы мне могли бы дать !!

Ответы [ 4 ]

2 голосов
/ 21 октября 2011

Вам не хватает вызова setTransactionSuccessful ().Пожалуйста, следуйте шаблону:

   db.beginTransaction();
   try {
     ...
     db.setTransactionSuccessful();
   } finally {
     db.endTransaction();
   }
1 голос
/ 24 августа 2011

Видимо, сейчас работает. Я поставил "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;'

но это не мешает исполнению моего кода .. сейчас.

Спасибо всем !!

Nico

0 голосов
/ 23 августа 2011

Взгляните на метод openOrCreateDatabase. Это, вероятно, имеет больше смысла для переопределения, просто подключившись к той части кода, где он создается.

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

0 голосов
/ 23 августа 2011

Удалите ваше приложение и установите снова.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...