2012-03-20 40 views
6

我有一个现有的数据库基于SQLiteOpenHelper有几个版本和代码来升级它,并且工作正常。但是,如果用户安装应用程序的旧版本(预期数据库版本较低),它将会崩溃 - 使用它的ContentProvider无法访问数据库。我想阻止它崩溃,但我不想实际降级数据库 - 添加代码来做到这一点很痛苦。删除所有表格肯定会起作用,但从新文件开始更加清晰并且不易出错。好的架构来删除SQLiteOpenHelper.onDowngrade()中的数据库文件

这是什么数据库助手模样 - 没有什么特别

public class MyDbHelper extends SQLiteOpenHelper { 
    private static final int DATABASE_VERSION = 3; 
    private static final String DATABASE_NAME = "my.db"; 

    public MyDbHelper(Context context) { 
     super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    } 

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     onUpgrade(db, 0, DATABASE_VERSION); 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     if (newVersion < 1) db.execSQL("CREATE TABLE A..."); 
     if (newVersion < 2) db.execSQL("CREATE TABLE B..."); 
     if (newVersion < 3) db.execSQL("CREATE TABLE C..."); 
    } 

    @Override 
    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     // I'd like to delete the database here 
     // the only problem is that I can't from here 
     // since this is called in the middle of getWritableDatabase() 
     // and SQLiteDatabase has no .recreate() method. 
    } 
} 

可能的方式我想出这样做是:

  • 从外面开始:捕获异常的ContentProvider,删除文件并请求再次打开数据库。 - 我不喜欢那样,因为它不是提供者的责任。
  • 用我自己的那类,删除文件,而不是调用onDowngrade的副本替换SQLiteOpenHelper - 问题是,它的使用,我不能没有重复SQLiteDatabase太取代的SQLiteDatabase(如.lock())封装私处(这将可能导致在复制整个sqlite堆栈)。

有没有什么好的方法来做到这一点,或我必须去DROP TABLES的方式,例如,像描述的here

回答

9

我已经想通过扩展SQLiteOpenHelper很好地工作,我需要做的所有MyDbHelper是扩展这个类。

public abstract class DeletingSQLiteOpenHelper extends SQLiteOpenHelper { 
    private static final String TAG = DeletingSQLiteOpenHelper.class.getSimpleName(); 

    private final File mDatabaseFile; 

    public DeletingSQLiteOpenHelper(Context context, String name, CursorFactory factory, int version, 
      DatabaseErrorHandler errorHandler) { 
     super(context, name, factory, version, errorHandler); 
     mDatabaseFile = context.getDatabasePath(name); 
    } 

    public DeletingSQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) { 
     super(context, name, factory, version); 
     mDatabaseFile = context.getDatabasePath(name); 
    } 

    @Override 
    public synchronized SQLiteDatabase getWritableDatabase() { 
     try { 
      return super.getWritableDatabase(); 
     } catch (SQLiteDowngradeFailedException e) { 
      // that's our notification 
     } 

     // try to delete the file 
     mDatabaseFile.delete() 

     // now return a freshly created database 
     return super.getWritableDatabase(); 
    } 

    @Override 
    public final void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     // throwing a custom Exception to catch it in getWritableDatabase 
     throw new SQLiteDowngradeFailedException(); 
    } 

    // that's the exception 
    static class SQLiteDowngradeFailedException extends SQLiteException { 
     public SQLiteDowngradeFailedException() {} 

     public SQLiteDowngradeFailedException(String error) { 
      super(error); 
     } 
    } 
}