비동기 DAO 쿼리 작성

쿼리가 UI를 차단하지 않도록 Room은 기본 스레드에서 데이터베이스 액세스를 허용하지 않습니다. 이 제한사항은 DAO 쿼리를 비동기식으로 만들어야 함을 의미합니다. Room 라이브러리에는 비동기 쿼리 실행을 제공하는 여러 다양한 프레임워크와의 통합이 포함되어 있습니다.

DAO 쿼리는 세 가지 카테고리로 분류됩니다.

  • 원샷 쓰기 쿼리: 데이터베이스에서 데이터를 삽입하거나 업데이트하거나 삭제합니다.
  • 원샷 읽기 쿼리: 데이터베이스에서 데이터를 한 번만 읽고 그 시점의 데이터베이스 스냅샷과 함께 결과를 반환합니다.
  • 관찰 가능한 읽기 쿼리: 기본 데이터베이스 테이블이 변경될 때마다 데이터베이스에서 데이터를 읽고 이러한 변경사항을 반영하는 새 값을 내보냅니다.

언어 및 프레임워크 옵션

Room은 특정 언어 기능 및 라이브러리와의 상호 운용성을 위한 통합 지원을 제공합니다. 다음 표는 쿼리 유형 및 프레임워크에 기반한 관련 반환 유형을 보여줍니다.

쿼리 유형 Kotlin 언어 기능 RxJava Guava Jetpack 수명 주기
원샷 쓰기 코루틴(suspend) Single<T>, Maybe<T>, Completable ListenableFuture<T> N/A
원샷 읽기 코루틴(suspend) Maybe<T> Single<T> ListenableFuture<T> N/A
관찰 가능한 읽기 Flow<T> Flowable<T>, Publisher<T>, Observable<T> N/A LiveData<T>

이 가이드에서는 이러한 통합을 사용하여 DAO에서 비동기 쿼리를 구현할 수 있는 세 가지 가능한 방법을 보여줍니다.

Flow 및 코루틴을 사용하는 Kotlin

Kotlin은 서드 파티 프레임워크 없이 비동기 쿼리를 작성할 수 있는 언어 기능을 제공합니다.

  • Room 2.2 이상에서는 Kotlin의 Flow 기능을 사용하여 관찰 가능한 쿼리를 작성할 수 있습니다.
  • Room 2.1 이상에서는 suspend 키워드를 사용하여 Kotlin 코루틴으로 DAO 쿼리를 비동기식으로 만들 수 있습니다.

RxJava를 사용하는 자바

앱에서 자바 프로그래밍 언어를 사용하면 RxJava 프레임워크의 특수 반환 유형을 사용하여 비동기 DAO 메서드를 작성할 수 있습니다. Room은 다음 RxJava 2 반환 유형을 지원합니다.

또한 Room 2.3 이상에서는 RxJava 3을 지원합니다.

LiveData 및 Guava를 사용하는 자바

앱에서 자바 프로그래밍 언어를 사용하는데 RxJava 프레임워크는 사용하고 싶지 않다면 다음 대안을 사용하여 비동기 쿼리를 작성할 수 있습니다.

  • Jetpack의 LiveData 래퍼 클래스를 사용하여 관찰 가능한 비동기 쿼리를 작성할 수 있습니다.
  • Guava의 ListenableFuture<T> 래퍼를 사용하여 비동기 원샷 쿼리를 작성할 수 있습니다.

비동기 원샷 쿼리 작성

원샷 쿼리는 데이터베이스 작업으로, 한 번만 실행되며 실행 시점의 데이터 스냅샷을 가져옵니다. 다음은 비동기 원샷 쿼리를 보여주는 예입니다.

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

관찰 가능한 쿼리 작성

관찰 가능한 쿼리는 읽기 작업으로, 쿼리에서 참조하는 테이블이 변경될 때마다 새 값을 내보냅니다. 이를 사용하여 기본 데이터베이스의 항목이 삽입되거나 업데이트되거나 삭제될 때 표시된 항목 목록을 최신 상태로 유지할 수 있습니다. 다음은 관찰 가능한 쿼리를 보여주는 예입니다.

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

추가 리소스

비동기 DAO 쿼리에 관한 자세한 내용은 다음 추가 리소스를 참고하세요.

샘플

블로그