- 9 de junho de 2020
- Blog
Populando seu banco de dados Room [database] com dados pré-empacotados
A biblioteca de persistência de dados Room, parte da coleção de bibliotecas Android Architecture Components, facilitou a vida de muitos desenvolvedores ao simplificar o desenvolvimento e a manutenção de bancos de dados em aplicativos Android. No entanto, às vezes, precisamos que os dados estejam disponíveis logo quando abrimos o aplicativo ou que o aplicativo seja independente de conexão à internet. Além disso, não existe uma solução simples e direta para popular o banco de dados com dados pré-empacotados na própria APK da aplicação ou baixados de um servidor.
Para tanto, normalmente, faz-se a cópia dos dados de outro banco de dados. Isso demanda um grande esforço, já que existe a preocupação com o acesso ao banco, validação de esquema, sincronização de threads e travamento e leitura de arquivo. Outra possibilidade é popular o banco a partir de um arquivo de descrição dos dados, como XML, JSON ou CSV que, dentro da aplicação, é convertido em objetos. Essa opção também é custosa, já que demanda a implementação de todo um serviço que faça essa conversão.
Não mais. A partir da versão 2.2 do Room, é possível popular seu banco com dados oriundos de um arquivo .db. Para isso, podemos usar os métodos RoomDatabase.Builder#createFromAsset() e RoomDatabase.Builder#createFromFile(), dependendo de qual é a localização do seu banco de dados pré-empacotado. Neste artigo, mostrarei como usar esses métodos, além de algumas dicas para trabalhar com bancos de dados pré-empacotados.
Neste Gist, você encontrará o código original para a inicialização de um banco de dados de exemplo, sem o uso dos novos métodos fornecidos pelo Room. Ao longo do arquivo, ele será modificado para que a inicialização seja feita a partir de um banco de dados pré-empacotado.
Antes de mais nada, entenda a diferença entre os dois novos métodos:
RoomDatabase.Builder#createFromAsset()
Se o arquivo contendo o banco de dados pré-empacotado estiver dentro do diretório assets/, ou seja, se já estiver embarcado na aplicação, utilize createFromAsset(), passando o caminho para o arquivo dentro de assets/ como parâmetro. Deste modo, considerando que temos um caminho assets/databases/foobar.db, a inicialização do banco de dados fica:

Inicialização do banco de dados com RoomDatabase.Builder#createFromAsset()
RoomDatabase.Builder#createFromFile()
Agora, caso o arquivo não esteja embarcado na aplicação e seja, por exemplo, baixado de um servidor, utilize createFromAsset(), passando um objeto File como parâmetro. A inicialização deve ser feita da seguinte maneira:

Inicialização do banco de dados com RoomDatabase.Builder#createFromFile()
Com esses comandos, inicializar seu banco de dados fica bem rápido e simples. Mas existem alguns pontos que necessitam de uma atenção especial, já que podem complicar o que era para ser simples e a documentação pode ser não muito clara, às vezes até incompleta.
Arquivos .db são diferentes de arquivos .sqlite
O arquivo que vai ser embarcado com o aplicativo ou que vai ser baixado não é o script de criação ou população do banco de dados. Um arquivo .db é a exportação de um banco de dados já existente, com suas definições e dados descritos. Portanto, é necessário que o banco a ser importado seja criado de antemão. Recomendamos o uso do SQLite Browser para executar as queries de criação de tabelas e inserção de dados e exportar o arquivo .db.
Caso o arquivo pré-empacotado esteja errado, o Room irá lançar uma RuntimeException: “Cannot copy database file”. Além disso, não esqueça que o Room copia o arquivo ao invés de apenas o abrir, portanto, o arquivo deve ter permissões de leitura.
Os bancos de dados devem seguir o mesmo schema
O SQL (Structured Query Language ou Linguagem de Consulta Estruturada) deve seguir a mesma representação de modelos do banco de dados Room, já que ele valida a estrutura do banco não apenas em uma migração, mas também na criação a partir de outro banco de dados. Para que isso seja realizado de forma bastate simples, basta que o parâmetro exportSchema do Room seja verdadeiro.

Parâmetro exportSchema verdadeiro
Desta forma, quando a aplicação for compilada, uma pasta schemas será gerada dentro da pasta app do projeto. Dentro dessa pasta, será criado um arquivo JSON com o schema do seu banco de dados Room. Este arquivo contém todas as queries para a criação das tabelas.

JSON com o schema do seu banco de dados Room
Caso o SQL banco de dados pré-empacotado não esteja refletindo a mesma representação de modelos, o Room lançará uma exceção SqliteException: “Database file is corrupt”.
Neste Gist você encontrará o arquivo .sqlite usado para criar o banco de dados externo, o arquivo .db que é pré-empacotado no aplicativo e o schema completo que representa a estrutura do banco de dados Room da aplicação.
Desta forma, tornou-se muito mais simples criar aplicativos com dados 100% offline ou importados de um banco de dados externo, tirando proveito da proteção de integridade dos dados provida pela biblioteca Room.