2010-07-02 3 views
33

Является ли метод onUpgradeSQLiteOpenHelper когда-либо называемым? Если да, то когда это называется и чем? Если он не вызывается разработчиками, то почему он там? Что на самом деле происходит с этой функцией? Я видел примеры, когда он отбрасывает все таблицы, но затем в комментарии говорится, что удаление всех таблиц - это не то, что вы должны делать. Какие-либо предложения?Является ли метод onUpgrade когда-либо называемым?

ответ

20

Он вызывается при построении SQLiteOpenHelper с версией, более новой, чем версия открытой базы данных. Что делать, зависит от изменений в базе данных, которые сделаны между старой и новой версиями. Единственный случай, когда вы не отбрасываете измененную таблицу, - это изменение в примечании больше, чем добавленный столбец. Затем вы можете использовать инструкцию ALTER TABLE, чтобы добавить новый столбец в подпись таблицы.

+4

Это изменение также может быть связано с добавлением новых таблиц, и в этом случае вы не сможете удалить существующие таблицы. – CommonsWare

+3

Но как бы узнать заранее, что вы измените таблицу? Или вам просто нужно изменить метод каждый раз, когда вы публикуете обновление. –

+3

Вы знаете, когда вы меняете базу данных и добавляете другой случай в onUpgrade. Поэтому, когда пользователь обновляет приложение, SQLiteOpenHelper знает, что существующая база данных устарела и принимает соответствующее действие. Просмотрите часть источника Android для справки: http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=packages/SettingsProvider/src/com/android/providers /settings/DatabaseHelper.java – ognian

28

Если вы используете SQLiteOpenHelper, onUpgrade будет вызываться всякий раз, когда вы меняете версию БД. Для этого необходимо дополнительное требование. Имя db должно оставаться неизменным.

Old Version: 
dbName = "mydb.db" 
dbVersion = 1 

New Version: 
dbName = "mydb.db" 
dbVersion = 2 

в OnCreate поставщика контента создается экземпляр SQLiteOpenHelper, который принимает эти Params. Ваша реализация SQLiteOpenHelper будет выглядеть следующим образом:

public static final class MySQLiteOpenHelper extends SQLiteOpenHelper { 

     public MySQLiteOpenHelper(Context context, int dbVersion, String dbName) { 
      super(context, dbName, null, dbVersion); 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db) { 
      //Code to create your db here 
     } 

     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      // Code to upgrade your db here 
     } 

} 
+0

Спасибо !!! Теперь я наконец понял, как использовать onUpgrade :-) – marlar

+0

@ dev.serghini Где вы находите информацию о том, что изменение имени версии БД запускает только 'onUpgrade'? Мне нужно официальное подтверждение этого, и я не могу найти его в официальных java-документах этого метода. – sandalone

+2

, так что возникает новый вопрос: когда изменилась «dbVersion»? делает ли разработчик это? как «appVersion» приложения? – sports

36

Для тех из вас, кто хотел бы знать точный момент, когда onUpgrade() вызывается, то во время вызова либо getReadableDatabase() или getWriteableDatabase().

Для тех, кто не ясно, как он обеспечивает его запуск, ответ таков: он запускается, когда обновляется версия базы данных, предоставленная конструктору SqLiteOpenHelper. Вот пример

public class dbSchemaHelper extends SQLiteOpenHelper { 

private String sql; 
private final String D_TAG = "FundExpense"; 
//update this to get onUpgrade() method of sqliteopenhelper class called 
static final int DB_VERSION = 2; 
static final String DB_NAME = "fundExpenseManager"; 

public dbSchemaHelper(Context context) { 
    super(context, DB_NAME, null, DB_VERSION); 
    // TODO Auto-generated constructor stub 
} 

теперь ... onUpgrade()

@Override 
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) { 
    sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER"; 
    arg0.execSQL(sql); 
} 
+2

На самом деле onUpgrade вызывается только при вызове getWriteableDatabase(). –

+0

спасибо за это объяснение –

+1

@DoctororDrive - также вызываемый 'getReadableDatabase()'; оба вызова 'getDatabaseLocked (boolean writeable)' – CJBS

4

Просмотр всех сообщений и запуск отладки кода он до сих пор не было ясно для меня, когда я хотел бы видеть onUpgrade вызывался. Я начал думать, что у Android был серьезный недостаток.

Информация на этой странице привела меня к моему окончательному решению. Спасибо, куча всем участникам!

Это решило для меня ...

public class DatabaseHelper extends SQLiteOpenHelper { 
    public static String TAG = DatabaseHelper.class.getName(); 
    private static final int DATABASE_VERSION = 42; 
    private static final String DATABASE_NAME = "app_database"; 
    private static final String OLD_TABLE = "old_and_useless"; 

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

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     if(newVersion > oldVersion) { 
      Log.d(TAG, "cool! you noticed."); 

      db.execSQL("DROP TABLE IF EXISTS " + OLD_TABLE); 
      // other calls like onCreate if necessary 

     } else { 
      Log.d(TAG, "Hey! didn't you see me?"); 
     } 

    } 

    public void checkDatabaseVersion() { 
     SQLiteDatabase db = this.getWritableDatabase(); 

     // if the DATABASE_VERSION is newer 
     // onUpgrade is called before this is reached 
    } 


    // other code removed for readability... 
} 

Это правда, что getWritableDatabase() и getReadableDatabase() не приводит к вызову onUpgrade. Я не проверял другие методы, так как они соответствуют требованиям для моих нужд.

Keep чтение, кикер приходит ...

Этот код в моей первоначальной деятельности просветил меня, когда я, наконец, понял, что версия БД обновляла во время моей отладки ... тьфу!

DatabaseHelper dbHelper = new DatabaseHelper(this); 
dbHelper.checkDatabaseVersion(); 

Примечание: вызов конструктора DatabaseHelper обновляет дб версию

После вызова конструктора ДБ был помечен с новой версией. Убейте приложение перед вызовом getWritableDatabase() или getReadableDatabase(), и вы находитесь в новой версии. После этого новые исполнения никогда не вызывают метод onUpgrade, пока DATABASE_VERSION снова не будет увеличен. (вздох! Теперь кажется смехотворным явлением :)

Мое предложение - добавить ранние этапы своего приложения «checkDatabaseVersion()». В противном случае, если вы создаете объект SQLiteOpenHelper, убедитесь, что вы вызываете один из методов (getWritableDatabase(), getReadableDatabase() и т. Д.) До того, как ваше приложение умирает.

Надеюсь, это сэкономит кому-то еще такую ​​же царапину на голове !. ..: р

2

Глядя в SqliteOpenHelper исходного кода, мы можем знать onCreate(), onUpgrade() и onDowngrade дозвонились в getWritableDatabase() или getReadableDatabase() методе.

public SQLiteDatabase getWritableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(true); 
    } 
} 
public SQLiteDatabase getReadableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(false); 
    } 
} 

private SQLiteDatabase getDatabaseLocked(boolean writable) { 
    if (mDatabase != null) { 
     if (!mDatabase.isOpen()) { 
      // Darn! The user closed the database by calling mDatabase.close(). 
      mDatabase = null; 
     } else if (!writable || !mDatabase.isReadOnly()) { 
      // The database is already open for business. 
      return mDatabase; 
     } 
    } 
      . . . . . . 

     final int version = db.getVersion(); 
     if (version != mNewVersion) { 
      if (db.isReadOnly()) { 
       throw new SQLiteException("Can't upgrade read-only database from version " + 
         db.getVersion() + " to " + mNewVersion + ": " + mName); 
      } 

      db.beginTransaction(); 
      try { 
       if (version == 0) { 
        onCreate(db); 
       } else { 
        if (version > mNewVersion) { 
         onDowngrade(db, version, mNewVersion); 
        } else { 
         onUpgrade(db, version, mNewVersion); 
        } 
       } 
       db.setVersion(mNewVersion); 
       db.setTransactionSuccessful(); 
      } finally { 
       db.endTransaction(); 
      } 
     } 

     onOpen(db); 

     if (db.isReadOnly()) { 
      Log.w(TAG, "Opened " + mName + " in read-only mode"); 
     } 

     mDatabase = db; 
     return db; 
    } finally { 
     mIsInitializing = false; 
     if (db != null && db != mDatabase) { 
      db.close(); 
     } 
    } 
} 
1

Он на самом деле называется при вызове getReadableDatabase или getWritableDatabase.

Глубокое погружение:

Вы передаете номер версии в конструкторе SQLiteOpenHelper, который хранится в переменной с именем mNewVersion. Вот и все. На данный момент ничего не происходит.

Каждый раз, когда вы вызываете getReadableDatabase или getWritableDatabase, он вызывает метод, называемый getDatabaseLocked. Этот метод получит существующий номер версии базы данных и сравнит его с mNewVersion.

  1. Если база данных с указанным именем не существует, он будет вызывать onCreate
  2. Если новая версия больше старой версии она будет вызывать onUpgrade.
  3. Если новая версия ниже существующей версии, будет выбрано исключение.
  4. Если они равны, они будут открыты и откроют базу данных.

Что следует писать в onCreate и onUpgrade?

onCreate должен содержать код, который создает схему в первый раз.

Вы можете оставить onUpgrade пустой первый раз, так как он не будет называться в первый раз. Если вы хотите изменить структуру таблицы на более позднем этапе, этот код должен войти здесь.

SQLiteOpenHelper.java (Исходный код)

public SQLiteDatabase getWritableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(true); 
    } 
} 

public SQLiteDatabase getReadableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(false); 
    } 
} 

private SQLiteDatabase getDatabaseLocked(boolean writable) { 
    . 
    . 

    final int version = db.getVersion(); 

     if (version != mNewVersion) { 
      if (db.isReadOnly()) { 
       throw new SQLiteException("Can't upgrade read-only database from version " + 
         db.getVersion() + " to " + mNewVersion + ": " + mName); 
      } 

      db.beginTransaction(); 
      try { 
       if (version == 0) { 
        onCreate(db); 
       } else { 
        if (version > mNewVersion) { 
         onDowngrade(db, version, mNewVersion); 
        } else { 
         onUpgrade(db, version, mNewVersion); 
        } 
       } 
       db.setVersion(mNewVersion); 
       db.setTransactionSuccessful(); 
      } finally { 
       db.endTransaction(); 
      } 
     } 

     onOpen(db); 
} 
Смежные вопросы