Cómo guardar datos en una base de datos local usando Room Parte de Android Jetpack.
Las apps que controlan grandes cantidades de datos estructurados pueden beneficiarse con la posibilidad de conservar esos datos localmente. El caso de uso más común consiste en almacenar en caché datos relevantes para que el dispositivo no pueda acceder a la red, de modo que el usuario pueda explorar ese contenido mientras está sin conexión.
La biblioteca de persistencias Room brinda una capa de abstracción para SQLite que permite acceder a la base de datos sin problemas y, al mismo tiempo, aprovechar toda la tecnología de SQLite. En particular, Room brinda los siguientes beneficios:
- Verificación del tiempo de compilación de las consultas en SQL
- Anotaciones de conveniencia que minimizan el código estándar repetitivo y propenso a errores
- Rutas de migración de bases de datos optimizadas
Recomendamos utilizar Room en lugar de usar las APIs de SQLite directamente.
Configuración
Para usar Room en tu app, agrega las siguientes dependencias al archivo build.gradle.kts del módulo. Room 3.0 requiere KSP para el procesamiento de anotaciones.
Kotlin
dependencies { val room_version = "3.0.0" implementation("androidx.room3:room3-runtime:$room_version") ksp("androidx.room3:room3-compiler:$room_version") }
Groovy
dependencies { def room_version = "3.0.0" implementation "androidx.room3:room3-runtime:$room_version" ksp "androidx.room3:room3-compiler:$room_version" }
Componentes principales
Estos son los tres componentes principales de Room:
- La clase de la base de datos que contiene la base de datos y sirve como punto de acceso principal para la conexión subyacente a los datos persistentes de la app
- Las entidades de datos que representan tablas de la base de datos de tu app
- Los objetos de acceso a datos (DAOs) que proporcionan funciones que tu app puede usar para consultar, actualizar, insertar y borrar datos en la base de datos
La clase de base de datos proporciona a tu app instancias de los DAOs asociados con esa base de datos. A su vez, la app puede usar los DAOs para recuperar datos de la base de datos como instancias de objetos de entidad de datos asociados. La app también puede usar las entidades de datos definidas para actualizar filas de las tablas correspondientes o crear filas nuevas para su inserción. En la figura 1, se muestran las relaciones entre los diferentes componentes de Room.
Ejemplo de implementación
En esta sección, se presenta un ejemplo de implementación de una base de datos de Room con una sola entidad de datos y un DAO único.
Entidad de datos
El siguiente código define una entidad de datos User. Cada instancia de User representa una fila en una tabla user de en la base de datos de la app.
@Entity data class User( @PrimaryKey val uid: Int, @ColumnInfo(name = "first_name") val firstName: String, @ColumnInfo(name = "last_name") val lastName: String )
Para obtener más información sobre las entidades de datos de Room, consulta Cómo definir datos con entidades de Room.
Objeto de acceso a datos (DAO)
El siguiente código define un DAO llamado UserDao. UserDao proporciona los métodos que el resto de la app usa para interactuar con los datos de la tabla user.
@Dao interface UserDao { @Query("SELECT * FROM user") suspend fun getAll(): List<User> @Query("SELECT * FROM user WHERE uid IN (:userIds)") suspend fun loadAllByIds(userIds: IntArray): List<User> @Query( """ SELECT * FROM user WHERE first_name LIKE :first AND last_name LIKE :last LIMIT 1 """ ) suspend fun findByName(first: String, last: String): User @Insert suspend fun insertAll(vararg users: User) @Delete suspend fun delete(user: User) }
Para obtener más información sobre los DAOs, consulta Cómo acceder a los datos con DAO de Room.
Base de datos
Con el siguiente código, se define una clase AppDatabase para contener la base de datos.
AppDatabase define la configuración de la base de datos y sirve como el punto de acceso principal de la app a los datos persistentes. La clase de la base de datos debe cumplir con las siguientes condiciones:
- La clase debe tener una anotación
@Databaseque incluya un arrayentitiesque enumere todas las entidades de datos asociados con la base de datos. - Debe ser una clase abstracta que extienda
RoomDatabase. - Para cada clase DAO asociada con la base de datos, esta base de datos debe definir una función abstracta que no tome argumentos y muestre una instancia de la clase DAO.
@Database(entities = [User::class], version = 1) abstract class AppDatabase : RoomDatabase() { abstract fun userDao(): UserDao }
Nota: Si tu app se ejecuta en un solo proceso, debes seguir el
patrón de diseño singleton cuando crees una instancia de un AppDatabase
objeto. Cada instancia RoomDatabase es bastante costosa y rara vez necesitas acceder a varias instancias en un mismo proceso.
Si tu app se ejecuta en varios procesos, incluye enableMultiInstanceInvalidation() en tu invocación del creador de bases de datos. De esa manera, cuando tienes una instancia de AppDatabase en cada proceso, puedes invalidar el archivo de base de datos compartido en un proceso, y esta invalidación se propaga automáticamente a las instancias de AppDatabase dentro de otros procesos.
Uso
Después de definir la entidad de datos, el DAO y el objeto de base de datos, puedes usar el siguiente código para crear una instancia de la base de datos:
val db = Room.databaseBuilder<AppDatabase>(applicationContext, "database-name") .setDriver(AndroidSQLiteDriver()) .build()
Luego, puedes usar las funciones abstractas de AppDatabase para obtener una instancia del DAO. A su vez, puedes usar las funciones de la instancia del DAO para interactuar con la base de datos:
val userDao = db.userDao() val users: List<User> = userDao.getAll()
Recursos adicionales
Si deseas obtener más información sobre Room, consulta los siguientes recursos adicionales: