2010-07-02 15 views

Respuesta

20

Se llama cuando se construye un SQLiteOpenHelper con una versión más nueva que la versión de la base de datos abierta. Qué hacer depende de los cambios en la base de datos que se realizan entre la versión anterior y la nueva. El único caso en el que no descarta una tabla modificada es cuando el cambio marca más que una columna adicional. Luego puede usar la instrucción ALTER TABLE para agregar la nueva columna a la firma de la tabla.

+4

El cambio también podría estar agregando nuevas tablas, en cuyo caso puede que no se eliminen las tablas existentes. – CommonsWare

+3

Pero, ¿cómo saber de antemano que va a modificar una tabla? O simplemente tiene que cambiar el método cada vez que publica una actualización. –

+3

Usted sabe cuando está cambiando la base de datos y agrega otro caso en onUpgrade. Entonces, cuando el usuario actualiza la aplicación, SQLiteOpenHelper sabe que la base de datos existente está obsoleta y toma la acción correspondiente. Consulte una fuente de Android como referencia: http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob;f=packages/SettingsProvider/src/com/android/providers /settings/DatabaseHelper.java – ognian

28

si está utilizando SQLiteOpenHelper se llamará a la actualización siempre que cambie la versión de la base de datos. Existe un requisito adicional para que esto funcione. El nombre db debe permanecer igual.

Old Version: 
dbName = "mydb.db" 
dbVersion = 1 

New Version: 
dbName = "mydb.db" 
dbVersion = 2 

en el onCreate del proveedor de contenido se crea una instancia de la SQLiteOpenHelper que toma estos parametros. Su aplicación SQLiteOpenHelper se vería así:

public static final class MySQLiteOpenHelper extends SQLiteOpenHelper { 

     public MySQLiteOpenHelper(Context context, int dbVersion, String dbName) { 
      super(context, dbName, null, dbVersion); 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db) { 
      //Code to create your db here 
     } 

     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
      // Code to upgrade your db here 
     } 

} 
+0

¡Gracias! Ahora finalmente entendí cómo usar onUpgrade :-) – marlar

+0

@ dev.serghini ¿Dónde encontraste información de que cambiar el nombre de la versión de DB solo activa 'onUpgrade'? Necesito confirmación oficial para esto y no puedo encontrarlo en los documentos oficiales de Java de este método. – sandalone

+2

entonces surge una nueva pregunta: ¿Cuándo se cambia la "dbVersion"? ¿el desarrollador controla eso? como la "aplicaciónVersión" de la aplicación? – sports

36

Para aquellos de ustedes que le gustaría saber el momento exacto en que se llama a onUpgrade(), es durante una llamada a cualquiera de getReadableDatabase() o getWriteableDatabase().

Para aquellos que no están seguros de cómo se activa, la respuesta es: se activa cuando se actualiza la versión de la base de datos proporcionada al constructor de SqLiteOpenHelper. Aquí está un ejemplo

public class dbSchemaHelper extends SQLiteOpenHelper { 

private String sql; 
private final String D_TAG = "FundExpense"; 
//update this to get onUpgrade() method of sqliteopenhelper class called 
static final int DB_VERSION = 2; 
static final String DB_NAME = "fundExpenseManager"; 

public dbSchemaHelper(Context context) { 
    super(context, DB_NAME, null, DB_VERSION); 
    // TODO Auto-generated constructor stub 
} 

ahora a ... ONUPGRADE()

@Override 
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) { 
    sql = "ALTER TABLE " + fundExpenseSchema.Expense.TABLE_NAME + " ADD COLUMN " + fundExpenseSchema.Expense.FUNDID + " INTEGER"; 
    arg0.execSQL(sql); 
} 
+2

En realidad, se llama a OnUpgrade solo si llama a getWriteableDatabase(). –

+0

gracias por esta explicación –

+1

@DoctororDrive - también llamado en 'getReadableDatabase()'; ambos llaman 'getDatabaseLocked (boolean writeable)' – CJBS

4

de revisar todos los mensajes y la ejecución de código de depuración que todavía no estaba claro para mí cuando veía ONUPGRADE recibiendo llamadas. Estaba empezando a pensar que Android tenía un defecto grave ...

La información en esta página me llevó a mi resolución final. ¡Muchas gracias a todos los colaboradores!

Esto resolvió por mí ...

public class DatabaseHelper extends SQLiteOpenHelper { 
    public static String TAG = DatabaseHelper.class.getName(); 
    private static final int DATABASE_VERSION = 42; 
    private static final String DATABASE_NAME = "app_database"; 
    private static final String OLD_TABLE = "old_and_useless"; 

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

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     if(newVersion > oldVersion) { 
      Log.d(TAG, "cool! you noticed."); 

      db.execSQL("DROP TABLE IF EXISTS " + OLD_TABLE); 
      // other calls like onCreate if necessary 

     } else { 
      Log.d(TAG, "Hey! didn't you see me?"); 
     } 

    } 

    public void checkDatabaseVersion() { 
     SQLiteDatabase db = this.getWritableDatabase(); 

     // if the DATABASE_VERSION is newer 
     // onUpgrade is called before this is reached 
    } 


    // other code removed for readability... 
} 

Es cierto que getWritableDatabase() y getReadableDatabase() da lugar a la llamada ONUPGRADE. No revisé otros métodos ya que estos se ajustan a mis necesidades.

lectura Keep, el truco está llegando ...

Este código en mi actividad inicial me iluminó cuando finalmente me di cuenta de que la versión del DB fue la actualización de depuración durante mi ... uf!

DatabaseHelper dbHelper = new DatabaseHelper(this); 
dbHelper.checkDatabaseVersion(); 

NOTA: llamando al constructor DatabaseHelper actualiza la versión db

Después de la llamada al constructor, el PP fue etiquetado con la nueva versión. Elimina la aplicación antes de una llamada a getWritableDatabase() o getReadableDatabase() y estás en la nueva versión. A partir de entonces, las nuevas ejecuciones nunca llaman al método onUpgrade hasta que DATABASE_VERSION se incremente nuevamente. (suspiro! Ahora parece ridículamente obvio :)

Mi sugerencia es agregar algún tipo de "checkDatabaseVersion()" a las primeras etapas de su aplicación. Alternativamente, si crea un objeto SQLiteOpenHelper, asegúrese de llamar a uno de los métodos (getWritableDatabase(), getReadableDatabase(), etc.) antes de que muera su aplicación.

Espero que esto le ahorre a alguien más el mismo rasguño en la cabeza !. ..: p

2

buscando en el código fuente SqliteOpenHelper, podemos conocer onCreate(), onUpgrade() y onDowngrade ser llamado en getWritableDatabase() o getReadableDatabase() método.

public SQLiteDatabase getWritableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(true); 
    } 
} 
public SQLiteDatabase getReadableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(false); 
    } 
} 

private SQLiteDatabase getDatabaseLocked(boolean writable) { 
    if (mDatabase != null) { 
     if (!mDatabase.isOpen()) { 
      // Darn! The user closed the database by calling mDatabase.close(). 
      mDatabase = null; 
     } else if (!writable || !mDatabase.isReadOnly()) { 
      // The database is already open for business. 
      return mDatabase; 
     } 
    } 
      . . . . . . 

     final int version = db.getVersion(); 
     if (version != mNewVersion) { 
      if (db.isReadOnly()) { 
       throw new SQLiteException("Can't upgrade read-only database from version " + 
         db.getVersion() + " to " + mNewVersion + ": " + mName); 
      } 

      db.beginTransaction(); 
      try { 
       if (version == 0) { 
        onCreate(db); 
       } else { 
        if (version > mNewVersion) { 
         onDowngrade(db, version, mNewVersion); 
        } else { 
         onUpgrade(db, version, mNewVersion); 
        } 
       } 
       db.setVersion(mNewVersion); 
       db.setTransactionSuccessful(); 
      } finally { 
       db.endTransaction(); 
      } 
     } 

     onOpen(db); 

     if (db.isReadOnly()) { 
      Log.w(TAG, "Opened " + mName + " in read-only mode"); 
     } 

     mDatabase = db; 
     return db; 
    } finally { 
     mIsInitializing = false; 
     if (db != null && db != mDatabase) { 
      db.close(); 
     } 
    } 
} 
1

Se llama en realidad se cuando llame getReadableDatabase o getWritableDatabase.

inmersión profunda:

se pasa el número de versión en el constructor de SQLiteOpenHelper que se almacena en una variable llamada mNewVersion. Eso es. Nada sucede en este punto.

Cada vez que llame a getReadableDatabase o getWritableDatabase, llamará a un método llamado getDatabaseLocked. Este método obtendrá el número de versión existente de la base de datos y lo comparará con el mNewVersion.

  1. Si no existe la base de datos con el nombre dado se llama onCreate
  2. Si la nueva versión es mayor que la vieja versión se llamará onUpgrade.
  3. Si la nueva versión es más baja que la versión existente, se lanzará una excepción.
  4. Si son iguales, continuará y abrirá la base de datos.

¿Qué debo escribir en onCreate y onUpgrade?

onCreate debe contener el código que crea un esquema por primera vez.

Puede dejar onUpgrade vacío por primera vez ya que no se llamará la primera vez. Cuando desee cambiar la estructura de la tabla en una etapa posterior, ese código debería ir aquí.

SQLiteOpenHelper.java (Código fuente)

public SQLiteDatabase getWritableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(true); 
    } 
} 

public SQLiteDatabase getReadableDatabase() { 
    synchronized (this) { 
     return getDatabaseLocked(false); 
    } 
} 

private SQLiteDatabase getDatabaseLocked(boolean writable) { 
    . 
    . 

    final int version = db.getVersion(); 

     if (version != mNewVersion) { 
      if (db.isReadOnly()) { 
       throw new SQLiteException("Can't upgrade read-only database from version " + 
         db.getVersion() + " to " + mNewVersion + ": " + mName); 
      } 

      db.beginTransaction(); 
      try { 
       if (version == 0) { 
        onCreate(db); 
       } else { 
        if (version > mNewVersion) { 
         onDowngrade(db, version, mNewVersion); 
        } else { 
         onUpgrade(db, version, mNewVersion); 
        } 
       } 
       db.setVersion(mNewVersion); 
       db.setTransactionSuccessful(); 
      } finally { 
       db.endTransaction(); 
      } 
     } 

     onOpen(db); 
} 
Cuestiones relacionadas