2010-07-02 64 views
33

是否曾經呼叫onUpgrade方法SQLiteOpenHelper?如果是這樣,它什麼時候被調用,什麼時候調用?如果開發者沒有調用它,爲什麼它在那裏?這個功能真的發生了什麼?我已經看到了所有表格的例子,但是之後有評論說,放棄所有表格並不是你應該做的。有什麼建議麼?有沒有叫onUpgrade方法?

回答

20

當您使用比已打開的數據庫版本更新的版本構造SQLiteOpenHelper時,會調用它。要做什麼取決於舊版本和新版本之間的數據庫更改。唯一的情況是,當您不刪除更改的表格時,更改記錄的內容超過了添加的列。然後,您可以使用ALTER TABLE語句將新列添加到表簽名。

+4

該更改還可能是添加新表,在這種情況下,您可能不會刪除任何現有表。 – CommonsWare 2010-07-02 07:49:38

+3

但是如何提前知道你會修改表格?或者您每次發佈更新時都必須更改方法。 – 2010-07-02 13:26:11

+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 2010-07-02 13:42:53

28

如果您正在使用SQLiteOpenHelper,則每次更改數據庫版本時都會調用onUpgrade。 對此有一個額外的要求。數據庫名稱必須保持不變。

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

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

在onCreate的內容提供者中,您創建了一個採用這些參數的SQLiteOpenHelper實例。你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 2011-07-22 20:24:22

+0

@ dev.serghini你在哪裏發現改變DB版本名稱的信息只觸發'onUpgrade'?我需要官方確認,我無法在這種方法的官方java文檔中找到它。 – sandalone 2013-08-19 17:27:41

+2

因此出現了一個新問題:「dbVersion」何時更改?開發者是否控制這個?就像應用程序的「appVersion」一樣? – sports 2014-04-14 00:30:24

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

實際上,只有調用getWriteableDatabase()時纔會調用onUpgrade。 – 2014-01-13 15:59:25

+0

謝謝你的解釋 – 2014-03-05 05:20:42

+1

@DoctororDrive - 也調用'getReadableDatabase()';都調用'getDatabaseLocked(布爾可寫)' – CJBS 2014-09-12 21:32:09

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通話。我沒有檢查其他方法,因爲這些方法符合我的需求。

堅持讀書,起腳來了...

這段代碼在我最初的活動使我明白,當我終於明白了DB版本我調試期間更新...... 啊!

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

注:調用DatabaseHelper構造更新數據庫版本

構造函數調用後,該數據庫被標記爲新的版本。在調用getWritableDatabase()或getReadableDatabase()之前殺死應用程序,然後使用新版本。此後,新的執行從不調用onUpgrade方法,直到DATABASE_VERSION再次增加。 (感嘆!現在看起來很可笑 :)

我的建議是在應用程序的早期階段添加某種「checkDatabaseVersion()」。或者,如果你創建一個SQLiteOpenHelper對象,請確保你的應用程序死亡之前調用其中一種方法(getWritableDatabase(),getReadableDatabase()等))。

我希望這可以節省別人同樣的頭撓! ..:p

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或​​。

深入瞭解:

你傳入存儲在一個名爲mNewVersion變量SQLiteOpenHelper構造函數的版本號。而已。此時什麼都沒有發生。

每次調用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); 
} 
相關問題