2012-03-20 6 views
6

Ho un database esistente basato su SQLiteOpenHelper che ha diverse versioni e codice per aggiornarlo e funziona perfettamente. Ma nel caso in cui un utente installa una versione precedente dell'app (che si aspetta una versione di database inferiore) si bloccherà in questo momento - il ContentProvider che lo utilizza non può accedere al database. Mi piacerebbe impedirgli di andare in crash, ma non voglio in realtà effettuare il downgrade del database - aggiungere il codice per farlo sarebbe doloroso. Eliminare tutte le tabelle funzionerebbe sicuramente, ma iniziare con un nuovo file è più pulito e meno incline agli errori.Buono schema per eliminare il file di database in SQLiteOpenHelper.onDowngrade()

Questo è su ciò che l'aiutante di database sembra - niente di speciale

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

I modi possibili sono venuto fino a farlo sono:

  • farlo dal di fuori: eccezioni di cattura in ContentProvider, eliminare il file e richiedere nuovamente l'apertura del database. - Non mi piace perché non è responsabilità del provider.
  • Sostituzione SQLiteOpenHelper con la mia copia di quella classe che elimina il file invece di chiamare onDowngrade - Il problema è che si tratta di utilizzo dei pacchetti parti intime SQLiteDatabase (ad es .lock()) che non può sostituire senza duplicare SQLiteDatabase troppo (che sarebbe probabilmente avvenuta nel duplicare l'intero stack sqlite).

C'è un buon approccio per farlo o devo andare al modo DROP TABLES ad es. come descritto here?

risposta

9

Ho trovato un modo che funziona bene estendendo SQLiteOpenHelper e tutto ciò che devo fare in MyDbHelper è di estendere questa classe.

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