Google se compromete a impulsar la igualdad racial para las comunidades afrodescendientes. Obtén información al respecto.

Cómo guardar contenido en una base de datos local con Room

Room proporciona una capa de abstracción sobre SQLite que permite acceder a la base de datos sin problemas y, al mismo tiempo, aprovechar toda la potencia de SQLite.

Las apps que controlan grandes cantidades de datos estructurados pueden beneficiarse con la posibilidad de conservar esos datos localmente. El caso práctico más común es almacenar en caché datos relevantes. De esa manera, cuando el dispositivo no puede acceder a la red, el usuario de todos modos puede explorar ese contenido mientras está desconectado. Cualquier cambio de contenido iniciado por el usuario se sincroniza con el servidor una vez que el dispositivo vuelve a estar en línea.

Como Room se ocupa de estas inquietudes por ti, te recomendamos utilizar Room en lugar de SQLite. Sin embargo, si prefieres usar las API de SQLite directamente, lee Cómo guardar datos mediante SQLite.

Para usar Room en tu app, agrega las siguientes dependencias al archivo build.gradle de tu app:

    dependencies {
      def room_version = "2.2.5"

      implementation "androidx.room:room-runtime:$room_version"
      annotationProcessor "androidx.room:room-compiler:$room_version" // For Kotlin use kapt instead of annotationProcessor

      // optional - Kotlin Extensions and Coroutines support for Room
      implementation "androidx.room:room-ktx:$room_version"

      // optional - RxJava support for Room
      implementation "androidx.room:room-rxjava2:$room_version"

      // optional - Guava support for Room, including Optional and ListenableFuture
      implementation "androidx.room:room-guava:$room_version"

      // Test helpers
      testImplementation "androidx.room:room-testing:$room_version"
    }
    

Estos son los 3 componentes principales de Room:

  • Base de datos: Contiene el titular de la base de datos y sirve como punto de acceso principal para la conexión subyacente a los datos persistentes y relacionales de tu app.

    La clase anotada con @Database debe cumplir con las siguientes condiciones:

    • Ser una clase abstracta que extiende RoomDatabase
    • Incluir la lista de entidades asociadas con la base de datos dentro de la anotación
    • Contener un método abstracto que tenga 0 argumentos y muestre la clase anotada con @Dao

    En el entorno de ejecución, puedes adquirir una instancia de Database llamando a Room.databaseBuilder() o Room.inMemoryDatabaseBuilder().

  • Entidad: Representa una tabla dentro de la base de datos.

  • DAO: Contiene los métodos utilizados para acceder a la base de datos.

La app usa la base de datos de Room para obtener los objetos de acceso a los datos (DAO) asociados con esa base de datos. Luego, la app usa cada DAO para obtener entidades de la base de datos y guardar los cambios realizados en esas entidades en la base de datos. Por último, la app usa una entidad para obtener y configurar valores que corresponden a columnas de tabla dentro de la base de datos.

Esta relación entre los diferentes componentes de Room aparece en la Figura 1:

Figura 1: Diagrama de arquitectura de Room

En el siguiente fragmento de código, se muestra una configuración de base de datos de ejemplo con una entidad y un DAO:

User

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;
    }
    

UserDao

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);
    }
    

AppDatabase

Kotlin

    @Database(entities = arrayOf(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();
    }
    

Después de crear los archivos anteriores, obtendrás una instancia de la base de datos creada con el siguiente código:

Kotlin

    val db = Room.databaseBuilder(
                applicationContext,
                AppDatabase::class.java, "database-name"
            ).build()
    

Java

    AppDatabase db = Room.databaseBuilder(getApplicationContext(),
            AppDatabase.class, "database-name").build();
    

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 objeto AppDatabase. 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.

Para realizar una experiencia práctica con Room, prueba los codelabs Room de Android con un objeto View y Persistencias de Android. Si deseas explorar los ejemplos de código de Room, consulta los ejemplos de los componentes de la arquitectura de Android.