Richard Richard - 4 months ago 15
Android Question

Android - SQLitehelper onCreate overwrites copied database

Based on
this tutorial and the default notepad example by Google, I tried to create my own Database adapter super class.

Now the idea is to copy a pre-created db from my assets folder to my app database folder. I want to use my databasehelper's onCreate method to call the custom method copyDataBase

I don't get any IO errors, but what seems to happen is that the database is created, my custom database is copied over and then overwritten again.

Any ideas why the onCreate method would overwrite my copied database?

Please see my super dbadapter class that contains the custom helper class

public abstract class DbAdapter_Super {

protected static final String TAG = "MyAppDbAdapter";
protected DatabaseHelper mDbHelper;
protected SQLiteDatabase mDb;


protected static final String DB_PATH = "/data/data/com.android.myapp/databases/";
protected static final String DB_NAME = "MyAppDB";

protected static final int DB_VERSION = 1;

protected final Context mCtx;

protected static class DatabaseHelper extends SQLiteOpenHelper {

protected final Context mHelpCtx;

DatabaseHelper(Context context) {
super(context,DB_NAME,null,DB_VERSION);
this.mHelpCtx = context;
}

@Override
public void onCreate(SQLiteDatabase db) {

//Copy pre-created DB
try{
copyDataBase();}
catch (IOException e) {
throw new Error("Error copying database");
}
}

@Override
public void onOpen(SQLiteDatabase db){};

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS routes");
onCreate(db);
}

private void copyDataBase() throws IOException{
//Open your local db as the input stream
InputStream myInput = mHelpCtx.getAssets().open(DB_NAME);

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

//if the path doesn't exist first, create it
File f = new File( DB_PATH );
if ( !f.exists() )
f.mkdir();

//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[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}

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


/**
* Constructor - takes the context to allow the database to be
* opened/created
*
* @param ctx the Context within which to work
*/
public DbAdapter_Super(Context ctx) {
this.mCtx = ctx;
}

/**
* Open or create the database.
*
* @return this
* @throws SQLException if the database could be neither opened or created
*/
public DbAdapter_Super open() throws SQLException {
mDbHelper = new DatabaseHelper(mCtx);
mDb = mDbHelper.getWritableDatabase();
return this;
}

public void close() {
mDbHelper.close();
}

}


I would really like to keep this abstract super class as is. I just need to understand why the db would be copied over and then overwritten by a blank db. I've tested as much as I can and the db is copied correctly, but overwritten.

Any help would be GREATLY appreciated.

Thanks

Answer

Ok, well I couldn't force the dbhelper class to work exactely like I wanted. What I instead opted to do was make the copydatabase() method public to my dbadapter class. Then I created a checkdatabase method that simple checks if the db already exists.

So the trick was to overrride the dbhelper's onCreate to do nothing. Then, from my dbadapter class I simple checked if the database existed (using the helper's checkdatabase() method) and if it didn't, I just called the copydatase method.

The check method I added to helper class (based on example from link in my first post)

public boolean checkDataBase(){

    SQLiteDatabase checkDB = null;

    try{
        String myPath = DB_PATH + DB_NAME;
        checkDB = SQLiteDatabase.openDatabase(myPath, null, SQLiteDatabase.OPEN_READONLY);
        }
    catch(SQLiteException e){
         //database does't exist yet.
     }

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

     return checkDB != null ? true : false;
}

So I then changed the following part my in DBadapter class

public DbAdapter_Super open() throws SQLException {
       mDbHelper = new DatabaseHelper(mCtx);

       //check if db exisist        
       if (mDbHelper.checkDataBase() != true) 
          try{
              mDbHelper.copyDataBase();

             } 
          catch (IOException e) {
               throw new Error("Error copying database");
           }
        mDb = mDbHelper.getWritableDatabase();


       return this;
}

I'm sure I can still trim and optimize the dbadapter class and do better error handling. But for now, I'm finally able to have a abstract class that I can build table handlers from and it copies my pre-created database.

Thanks to everyone who posted. Dunno why I didn't think of it sooner.

Comments