2012-03-20 14 views
6

Tôi có một cơ sở dữ liệu hiện có dựa trên SQLiteOpenHelper có một số phiên bản và mã để nâng cấp nó và hoạt động tốt. Nhưng trong trường hợp người dùng cài đặt phiên bản cũ hơn của ứng dụng (dự kiến ​​phiên bản cơ sở dữ liệu thấp hơn) thì hiện tại nó sẽ bị lỗi - số ContentProvider sử dụng nó không thể truy cập cơ sở dữ liệu. Tôi muốn ngăn chặn nó bị rơi nhưng tôi không muốn hạ cấp cơ sở dữ liệu - việc thêm mã để làm điều đó sẽ là đau đớn. Rơi tất cả các bảng chắc chắn sẽ làm việc nhưng bắt đầu với một tập tin mới là imo sạch hơn và ít bị lỗi.Giản đồ tốt để xóa tệp cơ sở dữ liệu trong SQLiteOpenHelper.onDowngrade()

Đó là về những gì các helper cơ sở dữ liệu trông giống như - không có gì đặc biệt

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

Các cách có thể tôi đã đi lên để làm điều đó là:

  • làm nó từ bên ngoài: ngoại lệ catch trong ContentProvider, xóa tệp và yêu cầu mở lại cơ sở dữ liệu. - Tôi không thích điều đó vì nó không phải là trách nhiệm của nhà cung cấp.
  • Thay SQLiteOpenHelper với bản sao của riêng tôi của lớp đó mà xóa các tập tin thay vì gọi onDowngrade - Vấn đề là nó sử dụng bộ phận kín gói SQLiteDatabase (ví dụ .lock()) mà tôi không thể thay thế mà không trùng lặp SQLiteDatabase quá (mà có lẽ sẽ cho kết quả sao chép toàn bộ ngăn xếp sqlite).

Có cách nào tốt để làm điều đó hay tôi phải đi theo cách DROP TABLES ví dụ: như mô tả here?

Trả lời

9

Tôi đã tìm ra cách hoạt động tốt bằng cách mở rộng SQLiteOpenHelper và tất cả những gì tôi cần làm trong MyDbHelper là mở rộng lớp này.

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); 
     } 
    } 
} 
Các vấn đề liên quan