À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 preenchimento automático de um banco de dados. No Room 2.2.0 e versões mais recentes, você pode usar métodos de API para preencher automaticamente 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.
Preencher automaticamente usando um recurso de app
Para preencher automaticamente um banco de dados do Room usando um arquivo de banco de dados pré-empacotado localizado
em qualquer lugar do diretório assets/
, chame o método createFromAsset()
do objeto RoomDatabase.Builder
antes de chamar build()
:
Kotlin
Room.databaseBuilder(appContext, AppDatabase::class.java, "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.
Preencher automaticamente usando o sistema de arquivos
Para preencher automaticamente um banco de dados do Room usando 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 objeto
RoomDatabase.Builder
antes de chamar build()
:
Kotlin
Room.databaseBuilder(appContext, AppDatabase::class.java, "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. Em vez de abrir o arquivo designado diretamente, o Room
cria uma cópia dele. 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, ele descarta todas as tabelas no banco de dados e cria um banco 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 tenta preencher o banco de dados recém-recriado com o conteúdo desse arquivo após realizar a migração destrutiva.
Para mais informações sobre as migrações de banco de dados do Room, consulte Como migrar bancos de dados do Room.
As seções abaixo 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.java, "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 nesta 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, trata-se de uma migração de substituto.
- Como o método de builder
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 e o preenche 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 implementada com um banco de dados pré-empacotado
Suponha que o 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.java, "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 nesta situação:
- Como o banco de dados definido no app está na versão 3 e o banco de dados já instalado 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
migrate()
definido a fim de atualizar a instância do banco de dados no dispositivo para a versão 3, preservando os dados que já estão nesse banco. O Room não usa o arquivo de banco de dados pré-empacotado, porque ele usa esses arquivos somente 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 de várias etapas. Considere este 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.java, "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 nesta situação:
- Como o banco de dados definido no 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, trata-se de uma migração de substituto.
- Como o método de builder
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 e o preenche 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 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
migrate()
definido a fim de 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 preencher automaticamente um banco de dados do Room, consulte estes recursos.
Vídeos
- O que há de novo no Room (Conferência de Desenvolvedores Android, 2019)