-
Room And CoroutinesAndroid 2021. 6. 10. 09:27
Room-Coroutines을 요약, 정리하였다.
앱에서 coroutines과 Room을 사용하려면 Room 2.1로 업데이트하고 build.gradle 파일에 새 종속성을 추가한다.
(Kotlin 1.3.0 및 Coroutines 1.0.0 이상 필요)
implementation "androidx.room:room-coroutines:${versions.room}"
이제 DAO method를 업데이트하여 일시 중단(suspension) 기능을 사용할 수 있다.
@Dao interface UsersDao { @Query("SELECT * FROM users") suspend fun getUsers(): List<User> @Query("UPDATE users SET age = age + 1 WHERE userId = :userId") suspend fun incrementUserAge(userId: String) .... }
@Transaction method도 일시 중단될 수 있으며 다른 일시 중단 DAO 함수를 호출할 수 있다.
@Dao abstract class UsersDao { @Transaction open suspend fun setLoggedInUser(loggedInUser: User) { deleteUser(loggedInUser) insertUser(loggedInUser) } @Query("DELETE FROM users") abstract fun deleteUser(user: User) @Insert abstract suspend fun insertUser(user: User) }
Transaction 내부의 다른 DAO에서 일시 중단 기능을 호출할 수도 있다.
class Repository(val database: MyDatabase) { suspend fun clearData(){ database.withTransaction { database.userDao().deleteLoggedInUser() // suspend function database.commentsDao().deleteComments() // suspend function } } }
Testing DAO suspension functions
DAO 일시 중지 기능을 테스트하는 것은 다른 일시 중지 기능을 테스트하는 것과 다르지 않다. 예를 들어, 사용자를 삽입 한 후 검색 할 수 있는지 확인하기 위해 runBlocking 블록으로 wrap한다.
@Test fun insertAndGetUser() = runBlocking { // Given a User that has been inserted into the DB userDao.insertUser(user) // When getting the Users via the DAO val usersFromDb = userDao.getUsers() // Then the retrieved Users matches the original user object assertEquals(listOf(user), userFromDb) }
Under the hood
Room이 synchronous 및 suspending insert을 위해 생성하는 DAO 클래스 구현을 살펴보자.
synchronous insert의 경우 생성된 코드는 트랜잭션을 시작하고 삽입을 실행하고 트랜잭션을 성공으로 표시하고 종료한다. synchronous method는 호출된 스레드에서 삽입만 실행한다.
@Override public void insertUserSync(final User user) { __db.beginTransaction(); try { __insertionAdapterOfUser.insert(user); __db.setTransactionSuccessful(); } finally { __db.endTransaction(); } }
이제 suspend를 추가하면 상황이 어떻게 변경되는지 살펴보자.
@Override public Object insertUserSuspend(final User user, final Continuation<? super Unit> p1) { return CoroutinesRoom.execute(__db, new Callable<Unit>() { @Override public Unit call() throws Exception { __db.beginTransaction(); try { __insertionAdapterOfUser.insert(user); __db.setTransactionSuccessful(); return kotlin.Unit.INSTANCE; } finally { __db.endTransaction(); } } }, p1); }
생성된 코드는 insert가 UI 스레드 외부에서 발생하도록 한다. Room은 데이터베이스가 열려있고 트랜잭션에 있는지 여부에 따라 background dispatcher로 전환되는 'CoroutinesRoom.execute' suspend function를 호출한다.
Case 1. 데이터베이스가 열려있고 트랜잭션 중일 경우 즉시 callable을 실행한다.
Case2. 그 외 경우
Room은 Callable#call 메서드에서 수행된 작업이 백그라운드 스레드에서 수행되는지 확인한다.
앱에서 Room 및 coroutine 사용하면 database 작업이 non-UI Dispatcher에서 실행되도록 보장된다.
'Android' 카테고리의 다른 글
ConstraintLayout(2) (0) 2021.06.13 ConstraintLayout(1) (0) 2021.06.11 LiveData beyond the ViewModel (0) 2021.06.04 LiveData (0) 2021.05.30 Android Kotlin Fundamentals - ViewModel(2) (0) 2021.05.30