En este artículo te quiero mostrar cuáles son los pasos para empezar a utilizar la librería de Room.
Room es una librería de base de datos creada por el equipo de Android en Google y que simplifica la tarea de trabajar con bases de datos en Android.
Room es tan fácil de usar, que en unos minutos tendrás una base de datos lista para ser usada.
Cómo funciona
La librería de Room actúa de intermediaria con la App. Lo que hacemos es pedirle el DAO que queremos usar, y el DAO nos devuelve una serie de Entities, que podemos modificar para actualizar la base de datos.
Tampoco te líes mucho con los conceptos porque lo veremos en el ejemplo
Añadir las dependencias de Room
Necesitas incluir el plugin kotlin-kapt
y las dos siguientes dependencias:
apply plugin: 'kotlin-kapt' dependencies { implementation "androidx.room:room-ktx:2.2.5" kapt "androidx.room:room-compiler:2.2.5" }
Como siempre, recuerda revisar las últimas versiones en la sección de releases de AndroidX.
Creamos las entidades que va a tener la base de datos
Si lo relacionamos con los conceptos típicos de una base de datos, estas entidades vendrían a ser las tablas.
Por ejemplo, si tenemos una entidad tipo persona como esta:
data class Person( val name: String, val age: Int, val address: String )
Lo único que necesitamos es añadir la anotación @Entity
para convertirlo en una entidad de Room:
@Entity data class Person( val name: String, val age: Int, val address: String )
Además, podemos añadirle un id que se autogenere, para identificar las distintas filas de la tabla:
@Entity data class Person( @PrimaryKey(autoGenerate = true) val id: Int, val name: String, val age: Int, val address: String )
Y ya está, esto nos creará una tabla de base de datos, ahora necesitaríamos poder hacer peticiones sobre esta tabla.
DAOs (o Data Access Objects)
Son los objetos que nos van a permitir acceder a los datos. Utilizando la anotación @Dao
es muy sencillo:
@Dao interface PersonDao { }
Los DAOs son interfaces, y cada método representa una operación de acceso o modificación de base de datos. Mediante anotaciones le indicamos qué operación van a realizar.
Acceso a datos
@Dao interface PersonDao { @Query("SELECT * from Person") fun getAll(): List<Person> }
Una cosa súper interesante es que Android Studio nos permite autocompletar y hacer validaciones sencillas de las queries que definimos:
A las queries también podemos pasarles argumentos. Solo tienes que indicar el argumento en la función, y lo podrás usar desde la query:
@Query("SELECT * FROM Person WHERE id = :id") fun findById(id: Int): Person
Creación de nuevos registros
Se realizan mediante la anotación @Insert
:
@Insert(onConflict = OnConflictStrategy.IGNORE) fun insert(people: List<Person>)
Gracias a onConflict, le podemos definir la estrategia de inserción si hay conflictos: IGNORE
, ABORT
o REPLACE
Actualización de registros
Es igual de fácil, pero con la anotación @Update
:
@Update fun update(person: Person)
Borrado de registros
Como ya te puedes imaginar a estas alturas, se haría con la anotación @Delete
:
@Delete fun delete(person: Person)
Creación de la base de datos
Este paso es muy sencillo. Solo tienes que crear la base de datos de Room, e identificar qué entidades va a utilizar y que DAOs puede proveer.
Hay que definirla como una clase abstracta que extienda de RoomDatabse
, y utilizar una serie de anotaciones que harán todo el trabajo sucio por nosotros:
@Database( entities = [Person::class], version = 1 ) abstract class PeopleDb : RoomDatabase() { abstract fun personDao(): PersonDao }
Para crear la instancia de Room, en el Application por ejemplo (si no usas inyección de dependencias):
val room: PeopleDb = Room .databaseBuilder(this, PeopleDb::class.java, "people") .build()
Y para usarlo:
val people = room.personDao().getAll()
Cómo evitar que Room se ejecute en el hilo principal
Todas estas operaciones de base de datos deberían hacerse fuera del hilo principal. Esto lo podemos hacer manualmente nosotros, o usar alguna de las integraciones que ya se nos dan implementadas.
Integración con corrutinas
Lo único que necesitamos es añadir la palabra suspend delante de las funciones del DAO, ¡y listo!
@Query("SELECT * from Person") suspend fun getAll(): List<Person>
Soluciones reactivas
Quizá preferimos que se nos informe cada vez que se modifiquen los elementos de la Query realizada. Para ello, lo que podemos hacer es usar alguna de las integraciones que tenemos con:
- LiveData
- Flow de Corrutinas
- RxJava
- Guava
Por ejemplo, con LiveData, es tan sencillo como devolver el objeto envuelto en un LiveData:
@Query("SELECT * from Person") suspend fun getAll(): LiveData<List<Person>>
Lo único que tendríamos que hacer sería observar ese LiveData.
Déjame en los comentarios si quieres que haga otro artículo hablando sobre alguna de las demás integraciones.
Y aquí puedes acceder al Gist con los distintos archivos.