为什么在Android sqlite数据库上没有调用onUpgrade()?

时间:2011-10-04 12:00:04

标签: android sqlite

我希望在将数据库安装到我的Android模拟器上时对其进行升级。 我在我的DbHelper中设置了db版本,它继承自SQLiteOpenHelper到+1。

然而,当我的第一个活动加载时,我实例化我的DbHelper,我希望SQLiteOpenHelper调用onUpgrade,因为db版本现在更新了。但它永远不会被称为。我想知道是否有我遗失的东西。 DbHelper使用的版本在哪里存储以与新版本进行比较?为什么这不起作用?

我实际上是将数据库从assets文件夹复制到数据文件夹,而不是重新创建架构。

public class DbHelper extends SQLiteOpenHelper {
    private static final String TAG = "DbHelper";

    static final String DB_NAME = "caddata.sqlite";
    static final int DB_VERSION = 4;

    private static String DB_PATH = "";
    private Context myContext;
    private SQLiteDatabase myDataBase;

    public DbHelper(Context context) {
        super(context, DB_NAME, null, DB_VERSION);
        this.myContext = context;

        DB_PATH = "/data/data/"
                + context.getApplicationContext().getPackageName()
                + "/databases/";            
    }

    public DbHelper open() throws SQLException {        
        myDataBase =  getWritableDatabase();

        Log.d(TAG, "DbHelper Opening Version: " +  this.myDataBase.getVersion());
        return this;
    }

    @Override
    public synchronized void close() {

        if (myDataBase != null)
            myDataBase.close();

        super.close();

    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.d(TAG, "onCreate called");

        try {           
            createDataBase();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        if ( newVersion > oldVersion)
        {
            Log.d(TAG, "New database version exists for upgrade.");         
            try {
                Log.d(TAG, "Copying database...");
                copyDataBase();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }       
        }
    }

    public void createDataBase() throws IOException {

        boolean dbExist = checkDataBase();

        if (!dbExist) {         

            try {
                copyDataBase();
            } catch (IOException e) {
                throw new Error("Error copying database");
            }
        }

        openDataBaseForRead();
    }


    private boolean checkDataBase() {

        SQLiteDatabase checkDB = null;

        try {
            String myPath = DB_PATH + DB_NAME;
            checkDB = SQLiteDatabase.openDatabase(myPath, null,
                    SQLiteDatabase.OPEN_READONLY
                            | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
            Log.d(TAG, "db exists");
        } catch (SQLiteException e) {
            // database does't exist yet.
            Log.d(TAG, "db doesn't exist");

        }

        if (checkDB != null) {
            checkDB.close();            
        }

        return checkDB != null ? true : false;
    }


    private void copyDataBase() throws IOException {

        // Open your local db as the input stream
        InputStream myInput = myContext.getAssets().open(DB_NAME);

        // Path to the just created empty db
        String outFileName = DB_PATH + DB_NAME;

        // Open the empty db as the output stream
        OutputStream myOutput = new FileOutputStream(outFileName);

        // transfer bytes from the inputfile to the outputfile
        byte[] buffer = new byte[2048];
        int length;
        while ((length = myInput.read(buffer)) > 0) {
            myOutput.write(buffer, 0, length);
        }

        // Close the streams
        myOutput.flush();
        myOutput.close();
        myInput.close();

        myDataBase.setVersion(DB_VERSION);
    }

    public void openDataBaseForRead() throws SQLException {

        // Open the database
        String myPath = DB_PATH + DB_NAME;      
        myDataBase = SQLiteDatabase.openDatabase(myPath, null,  SQLiteDatabase.OPEN_READONLY);
    }

    public void openDataBaseForWrite() throws SQLException {

        // Open the database
        String myPath = DB_PATH + DB_NAME;      
        myDataBase = SQLiteDatabase.openDatabase(myPath, null,  SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.NO_LOCALIZED_COLLATORS );
    }


}

4 个答案:

答案 0 :(得分:28)

这是SQLiteOpenHelper.getWritableDatabase()来源的代码段:

int version = db.getVersion();
if (version != mNewVersion) {
    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);

如您所见,onCreate()onUpgrade()getWritableDatabase()的调用中被调用。 只要您需要SQLiteDatabase的实例,就必须使用这些调用。您不应该使用自己的方法,除非它们是getWritableDatabasegetReadableDatabase方法的包装。

答案 1 :(得分:12)

Documentation说:

  

在调用getWritableDatabase()或getReadableDatabase()之一之前,实际上并未创建或打​​开数据库。

我发现您已经实现了自己的获取数据库的方法:openDataBaseForRead()openDataBaseForWrite()。那很糟糕; - )

答案 2 :(得分:3)

我已经找到了问题所在。 只有从资产中复制数据库时才会出现此问题。 assets文件夹中的db具有默认版本0.因此,当您使用版本号(例如1)调用数据库打开帮助程序,然后使用资产中的一个覆盖它时,版本号将重置为0.

当您调用应该调用onUpgrade方法的db.getReadableDatabase()或db.getWriteableDatabase时,它会失败,因为版本号0应该是一个新数据库。你可以查看SqliteOpenHelper的源代码。 仅当版本大于零且当前版本大于旧版本时,它才会触发onUpgrade方法。

`

db.beginTransaction();
try {
  //Skips updating in your case
  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();
}

`

所以这就是我为克服这个问题所做的。它没有完美的解决方案,但它的工作原理。基本上,在调用SQLiteOpenHelper类的超级方法(数据库管理器的构造函数)之前,需要更新db版本。

`

try
 {
   String myPath = MyApplication.context.getDatabasePath(DATABASE_NAME).toString();
   //open a database directly without Sqliteopenhelper 
   SQLiteDatabase myDataBase = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
   //if the version is default 0 the update the version
   if (myDataBase.getVersion() == 0)
    {
     //update the database version to the previous one
     myDataBase.execSQL("PRAGMA user_version = " + 1);
    }
    //Close DataBase 
    myDataBase.close();
  }
   catch (Exception e)
   {
     //Do Nothing a fresh install happened
   }

`

P.S:我知道答案很晚,但对于像我这样寻找这种特殊解决方案的人来说,这可能会有所帮助

答案 3 :(得分:0)

在我的情况下,资产文件夹中的数据库版本和代码中的当前数据库版本相同,后来我增加了代码中的当前数据库版本,然后调用了onUpgrade方法。