onUpgrade is not being called at first time in and

2019-04-01 01:49发布

问题:

I am facing a very strange problem. I am developing an android application that has an sqlite DB as its database. I am using DBAdapter class which extends SQLiteOpenHelper. I have searched on internet but can't find a solution.

Here is my SQLiteOpenHelper class

public class DBAdapter  extends SQLiteOpenHelper{

         private static DBAdapter mInstance = null;
        /**The Android's default system path of your application database. */
        private static String DB_PATH = "/data/data/com.mydbapp.android/databases/";

        private final static String DB_NAME = "mydb.sqlite";
        private static final int DATABASE_VERSION = 1;
        private static Context myContext;    


        public static DBAdapter getInstance(Context ctx) {

            if (mInstance == null) {
                mInstance = new DBAdapter(ctx);
            }
            return mInstance;
          }
            private DBAdapter(Context context) {     
                super(context,  DB_NAME, null, DATABASE_VERSION);
                DBAdapter.myContext = context;
                     DB_PATH = "/data/data/" +
                             context.getPackageName()+
                "/databases/"; 
            }   

           public void deleteDB()
           {
               myContext.deleteDatabase(DB_NAME);
           }

            public void createDataBase() throws IOException{     
                boolean dbExist = checkDataBase();  
                if(dbExist )
                {
                   this.getWritableDatabase();
                }
                if(!dbExist){
                    this.getReadableDatabase();
                    try {     
                        copyDataBase();
                    } catch (IOException e) {     
                        e.printStackTrace();
                        throw new Error("Error copying database");     
                    }
                }
            }

            @Override
            public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
            {
                if (newVersion > oldVersion)
                {
                            System.out.println("DB Upgrade logic")
                        }
            }

Now when I change private static final int DATABASE_VERSION = 2; then onUpgrade() method doesn't get invoked, but when I change private static final int DATABASE_VERSION = 3; then onUpgrade() works. So my question is that why doesn't it invoke the onUpgrade() method when I change DB version from 1 to 2. Please help me resolve this issue.

Edit 1

I have noticed one more strange behavior. When I initially run application with DB version 1 and then again I install application with sane DB version (1) and now if I change DB version 1 to 2, then onUpgrade() is called. What I mean to say is that I have to install application 2 times with same DB version then if I change DB version, onUpgrade() is called.

回答1:

Likely the database you're copying as the initial database already has it's schema version as 2.

Some other issues:

  • You should store the result of getWritableDatabase() or getReadableDatabase() and close() it when done.

  • This

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

    won't work on all devices. Don't hardcode database paths. Use getDatabasePath() instead.



回答2:

Try this way

When you use DBHelper class, onUpgrade() mehtod will be automatically called when you change db version. You don't need to compare with old and new version. you can remove comparison of version. it will help you. check below code for more clearification.

public class DBHelper extends SQLiteOpenHelper {

    // Static Final Variable database meta information

    static final String DATABASE = "empapp.db";
    static final int VERSION = 1;
    static final String TABLE = "emp";
    static final String TABLE_DEPT = "dept";

    static final String C_ID = "_id";
    static final String C_ENAME = "ename";
    static final String C_DESIGNATION = "designation";
    static final String C_SALARY = "salary";

   // Override constructor
    public DBHelper(Context context) {
        super(context, DATABASE, null, VERSION);

   }

    // Override onCreate method
    @Override
    public void onCreate(SQLiteDatabase db) {

        // Create Employee table with following fields
        // _ID, ENAME, DESIGNATION and SALARY
        db.execSQL("CREATE TABLE " + TABLE + " ( " + C_ID
            + " INTEGER PRIMARY KEY AUTOINCREMENT, " + C_ENAME + " text, "
            + C_DESIGNATION + " text, " + C_SALARY + " text )");
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        // Drop old version table
        db.execSQL("Drop table " + TABLE);

        // Create New Version table
        onCreate(db);
    }

}


回答3:

Okay, so behaviour you're describing is correct: If DB doesn't exit it runs onCreate If DB exists - it takes it version and runs onUpdate to the version you specify in constructor.

Apparently it is expected for you to create a newest version of DB in on create method for clean install and have code replicated partially in onUpgrade if user is updating app... If you're like me and think it's not a nice approach to dublicate code I suggest you doing this:

public const int VERSION = 2;

@Override
public void onCreate(SQLiteDatabase db) {
    // create a first version of your DB in this method only
    db.execSQL("CREATE TABLE " + TABLE + " ( " + C_ID
        + " INTEGER PRIMARY KEY AUTOINCREMENT, " + C_ENAME + " text, "
        + C_DESIGNATION + " text, " + C_SALARY + " text )");
    this.onUpgrade(db, 1, VERSION); // run onUpgrade manually
}

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    // Deal with all other versions separatelly
    for(int i = oldVersion + 1; i <= newVersion; i++) {
        switch(i) {
            case 2:
            db.execSQL("ALTER TABLE " + TABLE + " ADD COLUMN " + C_TAXES + " text;");
            break;
        }
    }
}

This approach is good if you don't want to lose data. If you don't care for data - then just make newest version of DB in onCreate and in onUpgrade - drop old DB and run onCreate.