Escribe consultas DAO asíncronas

Para evitar que las consultas bloqueen la IU, Room no permite el acceso a la base de datos en el subproceso principal. Esta restricción implica que tus búsquedas DAO deben ser asíncronas. La biblioteca de Room incluye integraciones con varios frameworks diferentes a fin de permitir la ejecución de búsquedas asíncronas.

Las búsquedas DAO se dividen en tres categorías:

  • Búsquedas de escritura única que insertan, actualizan o borran datos en la base de datos.
  • Búsquedas de lectura única que leen datos de tu base de datos solo una vez y muestran un resultado con la instantánea de la base de datos en ese momento.
  • Búsquedas de lectura observable que leen datos de tu base de datos cada vez que cambian las tablas de la base de datos subyacentes y emiten valores nuevos para reflejar esos cambios.

Opciones de framework y lenguaje

Room admite la interoperabilidad con funciones de lenguaje y bibliotecas específicas. En la siguiente tabla, se muestran los tipos de devolución aplicables según el tipo de búsqueda y el framework:

Tipo de búsqueda Funciones del lenguaje Kotlin RxJava Guava Ciclo de vida de Jetpack
Escritura por única vez Corrutinas (suspend) Single<T>, Maybe<T>, Completable ListenableFuture<T> N/A
Lectura de una toma Corrutinas (suspend) Single<T>, Maybe<T> ListenableFuture<T> N/A
Lectura observable Flow<T> Flowable<T>, Publisher<T>, Observable<T> N/A LiveData<T>

En esta guía, se muestran tres formas posibles de usar estas integraciones para implementar búsquedas asíncronas en tus DAO.

Kotlin con flujo y corrutinas

Kotlin ofrece las siguientes funciones de lenguaje que te permiten escribir consultas asíncronas sin frameworks de terceros:

  • En Room 2.2 y versiones posteriores, puedes usar la funcionalidad Flow de Kotlin para escribir consultas observables.
  • En Room 2.1 y versiones posteriores, puedes usar la palabra clave suspend para que tus consultas DAO sean asíncronas mediante corrutinas de Kotlin.

Java con RxJava

Si tu app usa el lenguaje de programación Java, puedes usar tipos de datos que se muestran especializados desde el framework de RxJava para escribir métodos DAO asíncronos. Room proporciona compatibilidad con los siguientes tipos de datos que se muestran de RxJava 2:

Además, Room 2.3 y versiones posteriores son compatibles con RxJava 3.

Java con LiveData y Guava

Si tu app usa el lenguaje de programación Java y no deseas utilizar el marco de trabajo de RxJava, puedes usar las siguientes alternativas para escribir búsquedas asíncronas:

  • Puedes usar la clase de wrapper LiveData de Jetpack para escribir consultas observables asíncronas.
  • Puedes usar el wrapper ListenableFuture<T> de Guava para escribir consultas asíncronas únicas.

Escritura de búsquedas asíncronas únicas

Las búsquedas únicas son operaciones de base de datos que solo se ejecutan una vez y toman una instantánea de los datos en el momento de la ejecución. Estos son algunos ejemplos de búsquedas asíncronas únicas:

Kotlin

@Dao
interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertUsers(vararg users: User)

    @Update
    suspend fun updateUsers(vararg users: User)

    @Delete
    suspend fun deleteUsers(vararg users: User)

    @Query("SELECT * FROM user WHERE id = :id")
    suspend fun loadUserById(id: Int): User

    @Query("SELECT * from user WHERE region IN (:regions)")
    suspend fun loadUsersByRegion(regions: List<String>): List<User>
}

Java

@Dao
public interface UserDao {
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public Completable insertUsers(List<User> users);

    @Update
    public Completable updateUsers(List<User> users);

    @Delete
    public Completable deleteUsers(List<User> users);

    @Query("SELECT * FROM user WHERE id = :id")
    public Single<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public Single<List<User>> loadUsersByRegion(List<String> regions);
}

Java

@Dao
public interface UserDao {
    // Returns the number of users inserted.
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    public ListenableFuture<Integer> insertUsers(List<User> users);

    // Returns the number of users updated.
    @Update
    public ListenableFuture<Integer> updateUsers(List<User> users);

    // Returns the number of users deleted.
    @Delete
    public ListenableFuture<Integer> deleteUsers(List<User> users);

    @Query("SELECT * FROM user WHERE id = :id")
    public ListenableFuture<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public ListenableFuture<List<User>> loadUsersByRegion(List<String> regions);
}

Escritura de búsquedas observables

Las búsquedas observables son operaciones de lectura que emiten valores nuevos cada vez que hay cambios en cualquiera de las tablas a las que hace referencia la búsqueda. Una forma de usarlas es para ayudarte a mantener actualizada una lista de elementos a medida que se insertan, actualizan o quitan los elementos de la base de datos subyacente. Los siguientes son ejemplos comunes de búsquedas observables:

Kotlin

@Dao
interface UserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    fun loadUserById(id: Int): Flow<User>

    @Query("SELECT * from user WHERE region IN (:regions)")
    fun loadUsersByRegion(regions: List<String>): Flow<List<User>>
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    public Flowable<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public Flowable<List<User>> loadUsersByRegion(List<String> regions);
}

Java

@Dao
public interface UserDao {
    @Query("SELECT * FROM user WHERE id = :id")
    public LiveData<User> loadUserById(int id);

    @Query("SELECT * from user WHERE region IN (:regions)")
    public LiveData<List<User>> loadUsersByRegion(List<String> regions);
}

Recursos adicionales

Si deseas obtener más información sobre las búsquedas DAO asíncronas, consulta los siguientes recursos adicionales:

Blogs