SQLiteOpenHelper
的onUpgrade
方法是否会被调用?如果会,那么它是在什么时候被调用的?由谁调用?如果开发人员不调用它,那么它为什么存在?这个函数到底做了什么?我看到一些示例中它会删除所有表,但是有一个注释说不应该这样做。有什么建议吗?
SQLiteOpenHelper
的onUpgrade
方法是否会被调用?如果会,那么它是在什么时候被调用的?由谁调用?如果开发人员不调用它,那么它为什么存在?这个函数到底做了什么?我看到一些示例中它会删除所有表,但是有一个注释说不应该这样做。有什么建议吗?
如果你想知道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);
}
如果你正在使用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
}
}
当您使用版本号高于已打开数据库版本的SQLiteOpenHelper构造函数时,会调用它。操作取决于旧版本和新版本之间所做的数据库更改。当更改仅仅是添加列时,唯一不需要删除更改表的情况就是使用ALTER TABLE语句将新列添加到表签名中。
在审查所有帖子并运行调试代码后,我仍然不清楚何时会调用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方法被调用。由于这些方法符合我的需求,我没有检查其他方法。
继续阅读,有一个重要提示...
在我最初的Activity中,这段代码让我恍然大悟,我终于意识到在调试期间数据库版本正在更新...呃!
DatabaseHelper dbHelper = new DatabaseHelper( this );
dbHelper.checkDatabaseVersion();
查看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();
}
}
}
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);
}
getReadableDatabase()
; 两者都调用了getDatabaseLocked(boolean writable)
。 - CJBS