I want to upgrade my database when it is installed onto my android emulator. I have set the db version in my DbHelper which inherits from SQLiteOpenHelper to +1.
However, when my 1st activity loads, I instantiate my DbHelper, which I would expect SQLiteOpenHelper to call onUpgrade as the db version is now newer. However it is never called. I'm wondering if there is something I am missing. Where is the version that the DbHelper is using stored to compare against the new version? Why is this not working?
I am actually copying the database from the assets folder into the data folder rather than re-creating the schema.
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 );
}
}
This is a code snippet from the source of 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);
As you can see, the onCreate()
or onUpgrade()
are called within the call to getWritableDatabase()
.
You have to use these calls whenever you need an instance of SQLiteDatabase
. You shouldn't use your own methods, except if they are wrappers arround the getWritableDatabase
or getReadableDatabase
method.
Documentation says:
The database is not actually created or opened until one of getWritableDatabase() or getReadableDatabase() is called.
I see that you've implemented your own methods for getting database: openDataBaseForRead()
and openDataBaseForWrite()
. That's bad ;-)
I have figured out the problem. This problem comes only when you copy the db from assets. The db in the assets folder has a default version 0. So when you call the database open helper with the version number(say 1) and then overwrite it with the one in assets the version number is reset to 0.
And when you call the db.getReadableDatabase() or db.getWriteableDatabase which is supposed to call the onUpgrade method, it fails because the version number 0 which is supposed to be a fresh database. you can look the source code of SqliteOpenHelper. It triggers the the onUpgrade method only when the version is greater than zero and the current version is greater than the old one.
`
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();
}
`
So this is what I did to overcome this issue. Its no where a perfect solution, but it works. Basically you need to update the db version before you call the super method of SQLiteOpenHelper class (your Database manager's constructor).
`
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: I know that the answer is late but, it might help for someone like me who was searching for this particular solution
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With