Android - SQLitehelper onCreate会覆盖复制的数据库

时间:2011-01-29 10:52:31

标签: android

基于 this教程和Google的默认记事本示例,我尝试创建自己的数据库适配器超类。

现在的想法是将预先创建的数据库从我的资源文件夹复制到我的应用程序数据库文件夹。我想使用databasehelper的onCreate方法来调用自定义方法copyDataBase

我没有得到任何IO错误,但似乎发生的是创建了数据库,我的自定义数据库被复制然后再次被覆盖。

为什么onCreate方法会覆盖我复制的数据库?

请参阅包含自定义帮助程序类

的超级dbadapter类
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();
    }

}

我真的想保留这个抽象的超类。我只需要理解为什么db会被复制,然后被空白db覆盖。我已尽可能多地测试并正确复制数据库,但已被覆盖。

任何帮助都会非常感激。

由于

4 个答案:

答案 0 :(得分:1)

好吧,我无法强迫dbhelper类像我想要的那样彻底工作。我反而选择做的是将copydatabase()方法公开给我的dbadapter类。然后我创建了一个checkdatabase方法,该方法可以简单地检查db是否已经存在。

所以诀窍是重写dbhelper的onCreate什么都不做。然后,从我的dbadapter类中,我简单地检查了数据库是否存在(使用helper的checkdatabase()方法),如果没有,我只调用了copydatase方法。

我添加到帮助程序类的检查方法(基于我在第一篇文章中的链接示例)

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;
}

然后我在DBadapter类中更改了以下部分

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;
}

我确信我仍然可以修剪和优化dbadapter类并做更好的错误处理。但是现在,我终于能够有一个抽象类,我可以从中构建表处理程序,它复制我预先创建的数据库。

感谢所有发帖的人。不知道我为什么不早点想到它。

答案 1 :(得分:1)

我对此问题的解决方案是添加onOpen() - 过程:

public class MySQLiteHelper extends SQLiteOpenHelper {
    private static final int DATABASE_VERSION = 2;
    ...

    @Override
    public void onOpen(SQLiteDatabase db) {
        int iversion = db.getVersion();
        if (iversion == 1) {
            onUpgrade(db, 1, 2);
        }
    }
}

答案 2 :(得分:0)

我认为您的onUpgrade不检查版本,因此始终执行drop table。 尝试类似:

onUpgrade(...) {
  if (newVersion > 1 ) {
    db.execute("drop table .. ");
  }
}

答案 3 :(得分:0)

每次调用DbAdapter_Super.open()时,都会创建DatabaseHelper的新实例,首次使用时会调用onCreate()方法。

为了避免这种情况,只需克隆一个DatabaseHelper的实例并将其缓存直至关闭:

public DbAdapter_Super open() throws SQLException {
    if(mDbHelper == null){
        mDbHelper = new DatabaseHelper(mCtx);
    }
    mDb = mDbHelper.getWritableDatabase();
    return this;
}

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

或者,如果您希望数据库在应用程序重新启动后继续存在,那么只需在重新创建数据库之前检查数据库是否已存在。