Às vezes, você pode querer que seu app comece com um banco de dados que já esteja carregado com um conjunto específico de dados. Isso é chamado de pré-preenchimento de um banco de dados. No Room 2.2.0 e versões posteriores, você pode usar métodos de API para preencher um banco de dados do Room na inicialização com conteúdo de um arquivo de banco de dados pré-empacotado no sistema de arquivos do dispositivo.
Pré-preencher a partir de um recurso de app
Para pré-preencher um banco de dados do Room a partir de um arquivo de banco de dados pré-empacotado localizado em qualquer lugar do assets/
diretório, chame o método createFromAsset()
do seu objeto RoomDatabase.Builder
antes de chamar build()
:
Kotlin
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .build()
Java
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .build();
O método createFromAsset()
aceita um argumento de string que contém um caminho relativo do diretório assets/
para o arquivo de banco de dados pré-empacotado.
Pré-preencher automaticamente a partir do sistema de arquivos
Para pré-preencher um banco de dados do Room a partir de um arquivo de banco de dados pré-empacotado localizado em qualquer lugar no sistema de arquivos do dispositivo exceto no diretório assets/
do app, chame o método createFromFile()
do seu objeto RoomDatabase.Builder
antes de chamar build()
:
Kotlin
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromFile(File("mypath")) .build()
Java
Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromFile(new File("mypath")) .build();
O método createFromFile()
aceita um argumento File
para o arquivo de banco de dados pré-empacotado. O Room cria uma cópia do arquivo designado em vez de abri-lo diretamente. Portanto, verifique se o app tem permissões de leitura no arquivo.
Processar migrações que incluem bancos de dados pré-empacotados
Os arquivos de banco de dados pré-empacotados também podem mudar a maneira como o banco de dados do Room gerencia migrações de substituto. Normalmente, quando as migrações destrutivas são ativadas e o Room precisa realizar uma migração sem um caminho de migração, o Room descarta todas as tabelas no banco de dados e cria um banco de dados vazio com o esquema especificado para a versão de destino. No entanto, se você incluir um arquivo de banco de dados pré-empacotado com o mesmo número da versão de destino, o Room tentará preencher o banco de dados recém-recriado com o conteúdo do arquivo de banco de dados pré-empacotado após a execução da migração destrutiva.
Para mais informações sobre as migrações de banco de dados do Room, consulte Migrating Room databases (link em inglês).
As seções a seguir apresentam alguns exemplos de como isso funciona na prática.
Exemplo: migração de substituto com um banco de dados pré-empacotado
Suponha que:
- seu app define um banco de dados do Room na versão 3.
- a instância do banco de dados instalada no dispositivo está na versão 2.
- há um arquivo de banco de dados pré-empacotado que está na versão 3.
- não há caminho de migração implementado da versão 2 para a versão 3.
- as migrações destrutivas estão ativadas.
Kotlin
// Database class definition declaring version 3. @Database(version = 3) abstract class AppDatabase : RoomDatabase() { ... } // Destructive migrations are enabled and a prepackaged database // is provided. Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .fallbackToDestructiveMigration() .build()
Java
// Database class definition declaring version 3. @Database(version = 3) public abstract class AppDatabase extends RoomDatabase { ... } // Destructive migrations are enabled and a prepackaged database // is provided. Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .fallbackToDestructiveMigration() .build();
Veja o que acontece na seguinte situação:
- Como o banco de dados definido no seu app está na versão 3 e a instância do banco de dados já instalada no dispositivo está na versão 2, é necessário fazer uma migração.
- Como não há um plano de migração implementado da versão 2 para a versão 3, a migração é uma migração de substituto.
- Como o método de criação
fallbackToDestructiveMigration()
é chamado, a migração de substituto é destrutiva. O Room descarta a instância do banco de dados instalada no dispositivo. - Como há um arquivo do banco de dados pré-empacotado que está na versão 3, o Room recria o banco de dados usando o conteúdo do arquivo pré-empacotado. Por outro lado, se o arquivo do banco de dados pré-empacotado estivesse na versão 2, o Room notaria que ele não corresponde à versão de destino e não o usaria como parte da migração de substituto.
Exemplo: migração de substituto com um banco de dados pré-empacotado
Suponha que seu app implemente um caminho de migração da versão 2 para a versão 3:
Kotlin
// Database class definition declaring version 3. @Database(version = 3) abstract class AppDatabase : RoomDatabase() { ... } // Migration path definition from version 2 to version 3. val MIGRATION_2_3 = object : Migration(2, 3) { override fun migrate(database: SupportSQLiteDatabase) { ... } } // A prepackaged database is provided. Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .addMigrations(MIGRATION_2_3) .build()
Java
// Database class definition declaring version 3. @Database(version = 3) public abstract class AppDatabase extends RoomDatabase { ... } // Migration path definition from version 2 to version 3. static final Migration MIGRATION_2_3 = new Migration(2, 3) { @Override public void migrate(SupportSQLiteDatabase database) { ... } }; // A prepackaged database is provided. Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .addMigrations(MIGRATION_2_3) .build();
Veja o que acontece na seguinte situação:
- Como o banco de dados definido no seu app está na versão 3 e o banco de dados já instalada no dispositivo está na versão 2, é necessário fazer uma migração.
- Como há um caminho de migração implementado da versão 2 para a versão 3, o Room executa o método definido
migrate()
para atualizar a instância do banco de dados no dispositivo para a versão 3, preservando os dados que já estão no banco de dados. O Room não usa o arquivo de banco de dados pré-empacotado, porque ele usa arquivos de banco de dados pré-empacotados apenas no caso de uma migração de substituto.
Exemplo: migração em várias etapas com um banco de dados pré-empacotado
Os arquivos de banco de dados pré-empacotados também podem afetar migrações em várias etapas. Considere o seguinte caso:
- Seu app define um banco de dados do Room na versão 4.
- A instância do banco de dados instalada no dispositivo está na versão 2.
- Há um arquivo de banco de dados pré-empacotado que está na versão 3.
- Há um caminho de migração implementado da versão 3 para a versão 4, mas não da versão 2 para a versão 3.
- As migrações destrutivas estão ativadas.
Kotlin
// Database class definition declaring version 4. @Database(version = 4) abstract class AppDatabase : RoomDatabase() { ... } // Migration path definition from version 3 to version 4. val MIGRATION_3_4 = object : Migration(3, 4) { override fun migrate(database: SupportSQLiteDatabase) { ... } } // Destructive migrations are enabled and a prepackaged database is // provided. Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .addMigrations(MIGRATION_3_4) .fallbackToDestructiveMigration() .build()
Java
// Database class definition declaring version 4. @Database(version = 4) public abstract class AppDatabase extends RoomDatabase { ... } // Migration path definition from version 3 to version 4. static final Migration MIGRATION_3_4 = new Migration(3, 4) { @Override public void migrate(SupportSQLiteDatabase database) { ... } }; // Destructive migrations are enabled and a prepackaged database is // provided. Room.databaseBuilder(appContext, AppDatabase.class, "Sample.db") .createFromAsset("database/myapp.db") .addMigrations(MIGRATION_3_4) .fallbackToDestructiveMigration() .build();
Veja o que acontece na seguinte situação:
- Como o banco de dados definido no seu app está na versão 4 e a instância do banco de dados já instalada no dispositivo está na versão 2, é necessário fazer uma migração.
- Como não há um caminho de migração implementado da versão 2 para a versão 3, a migração é uma migração de substituto.
- Como o método de criação
fallbackToDestructiveMigration()
é chamado, a migração de substituto é destrutiva. O Room descarta a instância do banco de dados no dispositivo. - Como há um arquivo do banco de dados pré-empacotado que está na versão 3, o Room recria o banco de dados usando o conteúdo do arquivo pré-empacotado.
- O banco de dados instalado no dispositivo agora está na versão 3. Como essa versão ainda é anterior à versão definida no seu app, é necessário fazer outra migração.
- Como há um caminho de migração implementado da versão 3 para a versão 4, o Room executa o método definido
migrate()
para atualizar a instância do banco de dados no dispositivo para a versão 4, preservando os dados copiados de banco de dados pré-empacotado da versão 3.
Outros recursos
Para saber mais sobre como pré-preencher um banco de dados do Room, consulte os seguintes recursos adicionais.
Vídeos
- O que há de novo no Room (Conferência de Desenvolvedores Android, 2019)