Criar consultas DAO assíncronas

Para impedir que as consultas bloqueiem a IU, o Room não permite o acesso ao banco de dados na linha de execução principal. Devido a essa restrição, é necessário fazer com que as consultas DAO sejam assíncronas. A biblioteca do Room inclui integrações com vários frameworks diferentes para oferecer a execução de consulta assíncrona.

As consultas DAO se enquadram em três categorias:

  • Consultas de gravação única, que inserem, atualizam ou excluem dados do banco de dados.
  • Consultas de leitura única, que leem dados do banco de dados apenas uma vez e retornam um resultado com um snapshot do banco de dados naquele momento.
  • Consultas de leitura observável, que leem dados do banco de dados sempre que as tabelas subjacentes mudam e emitem novos valores para refletir essas mudanças.

Opções de linguagem e framework

O Room oferece suporte de integração para interoperabilidade com bibliotecas e recursos de linguagem específicos. A tabela abaixo mostra os tipos de retorno aplicáveis de acordo com o tipo de consulta e framework:

Tipo de consulta Recursos da linguagem Kotlin RxJava Guava Ciclo de vida do Jetpack
Gravação única Corrotinas (suspend) Single<T>, Maybe<T>, Completable ListenableFuture<T> N/A
Leitura única Corrotinas (suspend) Single<T>, Maybe<T> ListenableFuture<T> N/A
Leitura observável Flow<T> Flowable<T>, Publisher<T>, Observable<T> N/A LiveData<T>

Este guia demonstra três maneiras possíveis de usar essas integrações para implementar consultas assíncronas nos DAOs.

Kotlin com fluxo e corrotinas

O Kotlin oferece recursos de linguagem que permitem criar consultas assíncronas sem frameworks de terceiros:

  • No Room 2.2 e versões mais recentes, é possível usar as Fluxo para escrever consultas observáveis.
  • No Room 2.1 e versões mais recentes, é possível usar a palavra-chave suspend para tornar as consultas do DAO assíncronas, usando corrotinas do Kotlin.

Java com RxJava

Se o app usa a linguagem de programação Java, é possível usar tipos de retorno especializados do framework RxJava para programar métodos DAO assíncronos. O Room oferece suporte a estes tipos de retorno RxJava 2:

Além disso, o Room 2.3 e versões mais recentes oferecem suporte ao RxJava 3.

Java com LiveData e Guava

Se o app usa a linguagem de programação Java e você não quer usar o framework RxJava, é possível usar estas alternativas para programar consultas assíncronas:

  • Você pode usar a classe de wrapper LiveData do Jetpack para programar consultas observáveis assíncronas.
  • Você pode usar o ListenableFuture<T> wrapper do Guava para escrever consultas assíncronas únicas.

Criar consultas assíncronas únicas

Consultas únicas são operações de banco de dados que são executadas apenas uma vez e capturam um snapshot dos dados durante a execução. Veja abaixo alguns exemplos de consultas assí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);
}

Criar consultas observáveis

Consultas observáveis são operações de leitura que emitem novos valores sempre que há mudanças em qualquer uma das tabelas referenciadas pela consulta. Essa função pode ser usada para ajudar a manter uma lista de itens exibida atualizada à medida que os itens no banco de dados são inseridos, atualizados ou removidos. Veja abaixo alguns exemplos de consultas observáveis:

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

Outros recursos

Para saber mais sobre consultas DAO assíncronas, consulte os recursos abaixo recursos:

Exemplos

  • Exemplo do Room & RxJava (Java e Kotlin, links em inglês)

Blogs