Salvar dados em um banco de dados local usando Room Parte do Android Jetpack.
A persistência de dados local pode ser muito útil para apps que processam quantidades não triviais de dados estruturados. O caso de uso mais comum é armazenar em cache partes importantes de dados para que, quando o dispositivo não puder acessar a rede, o usuário ainda consiga ter acesso a esse conteúdo off-line.
A biblioteca de persistência Room oferece uma camada de abstração sobre o SQLite para permitir acesso fluente ao banco de dados, aproveitando toda a capacidade do SQLite. O Room oferece principalmente estes benefícios:
- Verificação de consultas SQL durante a compilação.
- Anotações de conveniência que minimizam o código boilerplate repetitivo e propenso a erros.
- Caminhos de migração de banco de dados simplificados.
Dessa forma, recomendamos que você use o Room em vez de usar diretamente as APIs SQLite.
Configurar
Para usar o Room no app, adicione as dependências abaixo ao arquivo
build.gradle
do app:
Groovy
dependencies { def room_version = "2.6.1" implementation "androidx.room:room-runtime:$room_version" annotationProcessor "androidx.room:room-compiler:$room_version" // To use Kotlin annotation processing tool (kapt) kapt "androidx.room:room-compiler:$room_version" // To use Kotlin Symbol Processing (KSP) ksp "androidx.room:room-compiler:$room_version" // optional - RxJava2 support for Room implementation "androidx.room:room-rxjava2:$room_version" // optional - RxJava3 support for Room implementation "androidx.room:room-rxjava3:$room_version" // optional - Guava support for Room, including Optional and ListenableFuture implementation "androidx.room:room-guava:$room_version" // optional - Test helpers testImplementation "androidx.room:room-testing:$room_version" // optional - Paging 3 Integration implementation "androidx.room:room-paging:$room_version" }
Kotlin
dependencies { val room_version = "2.6.1" implementation("androidx.room:room-runtime:$room_version") annotationProcessor("androidx.room:room-compiler:$room_version") // To use Kotlin annotation processing tool (kapt) kapt("androidx.room:room-compiler:$room_version") // To use Kotlin Symbol Processing (KSP) ksp("androidx.room:room-compiler:$room_version") // optional - Kotlin Extensions and Coroutines support for Room implementation("androidx.room:room-ktx:$room_version") // optional - RxJava2 support for Room implementation("androidx.room:room-rxjava2:$room_version") // optional - RxJava3 support for Room implementation("androidx.room:room-rxjava3:$room_version") // optional - Guava support for Room, including Optional and ListenableFuture implementation("androidx.room:room-guava:$room_version") // optional - Test helpers testImplementation("androidx.room:room-testing:$room_version") // optional - Paging 3 Integration implementation("androidx.room:room-paging:$room_version") }
Principais componentes
Existem três componentes principais no Room:
- A classe de banco de dados, que contém o banco de dados e serve como o ponto de acesso principal para a conexão com os dados persistidos do app.
- As entidades de dados, que representam tabelas no banco de dados do app.
- Os objetos de acesso a dados (DAOs, na sigla em inglês), que fornecem métodos que o app pode usar para consultar, atualizar, inserir e excluir dados do banco de dados.
A classe do banco de dados fornece ao app instâncias dos DAOs associadas ao banco de dados. O app pode usar os DAOs para extrair dados do banco de dados como instâncias dos objetos da entidade de dados associados. Ele também pode usar as entidades de dados definidas para atualizar linhas das tabelas correspondentes ou criar novas linhas para inserção. A Figura 1 mostra a relação entre os diferentes componentes do Room.
Exemplo de implementação
Nesta seção, apresentamos um exemplo de implementação de um banco de dados do Room com uma única entidade de dados e um único DAO.
Entidade de dados
O código abaixo define uma entidade de dados User
. Cada instância de User
representa uma linha em uma tabela user
no banco de dados do app.
Kotlin
@Entity data class User( @PrimaryKey val uid: Int, @ColumnInfo(name = "first_name") val firstName: String?, @ColumnInfo(name = "last_name") val lastName: String? )
Java
@Entity public class User { @PrimaryKey public int uid; @ColumnInfo(name = "first_name") public String firstName; @ColumnInfo(name = "last_name") public String lastName; }
Para saber mais sobre entidades de dados no Room, consulte Como definir dados usando entidades do Room.
Objeto de acesso a dados (DAO)
O código abaixo define um DAO com o nome UserDao
. O UserDao
fornece
os métodos que o restante do app usa para interagir com os dados na tabela user
.
Kotlin
@Dao interface UserDao { @Query("SELECT * FROM user") fun getAll(): List<User> @Query("SELECT * FROM user WHERE uid IN (:userIds)") fun loadAllByIds(userIds: IntArray): List<User> @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") fun findByName(first: String, last: String): User @Insert fun insertAll(vararg users: User) @Delete fun delete(user: User) }
Java
@Dao public interface UserDao { @Query("SELECT * FROM user") List<User> getAll(); @Query("SELECT * FROM user WHERE uid IN (:userIds)") List<User> loadAllByIds(int[] userIds); @Query("SELECT * FROM user WHERE first_name LIKE :first AND " + "last_name LIKE :last LIMIT 1") User findByName(String first, String last); @Insert void insertAll(User... users); @Delete void delete(User user); }
Para saber mais sobre os DAOs, consulte Como acessar dados usando DAOs do Room.
Banco de dados
O código abaixo define uma classe AppDatabase
para armazenar o banco de dados.
A classe AppDatabase
define a configuração do banco de dados e serve como o ponto de acesso
principal do app aos dados persistidos. A classe de banco de dados precisa atender a
estas condições:
- A classe precisa ter uma anotação
@Database
que inclua uma matrizentities
listando todas as entidades de dados associados ao banco de dados. - A classe precisa ser abstrata e estender
RoomDatabase
. - Para cada classe DAO associada ao banco de dados, a classe de banco de dados precisa definir um método abstrato que não tenha argumentos e retorne uma instância da classe DAO.
Kotlin
@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
Java
@Database(entities = {User.class}, version = 1) public abstract class AppDatabase extends RoomDatabase { public abstract UserDao userDao(); }
Observação: caso o app seja executado em um único processo, siga o
padrão singleton ao instanciar um objeto
AppDatabase
. Cada instância RoomDatabase
é bastante cara do ponto de vista computacional e raramente
é necessário ter acesso a várias instâncias em um único processo.
Caso o app seja executado em vários processos, inclua
enableMultiInstanceInvalidation()
ao invocar o builder do banco de
dados. Dessa forma, quando você tiver uma instância de AppDatabase
em cada processo, é possível invalidar o arquivo do banco de dados compartilhado em um processo.
Essa invalidação é automaticamente propagada para as instâncias de
AppDatabase
em outros processos.
Uso
Depois de definir a entidade de dados, o DAO e o objeto de banco de dados, é possível usar o código abaixo para criar uma instância do banco de dados:
Kotlin
val db = Room.databaseBuilder( applicationContext, AppDatabase::class.java, "database-name" ).build()
Java
AppDatabase db = Room.databaseBuilder(getApplicationContext(), AppDatabase.class, "database-name").build();
Em seguida, use os métodos abstratos da classe AppDatabase
para acessar uma instância
do DAO. Como alternativa, é possível usar os métodos da instância do DAO para interagir
com o banco de dados:
Kotlin
val userDao = db.userDao() val users: List<User> = userDao.getAll()
Java
UserDao userDao = db.userDao(); List<User> users = userDao.getAll();
Outros recursos
Para saber mais sobre o Room, consulte os recursos abaixo.
Exemplos
Codelabs
Blogs
- Sete dicas para o Room (em inglês)
- Migração incrementada do SQLite para Room (em inglês)