이 Codelab은 Android Kotlin 기초 교육 과정의 일부입니다. Codelab을 순서대로 진행한다면 이 과정을 통해 최대한의 가치를 얻을 수 있을 것입니다. 모든 과정 Codelab은 Android Kotlin 기초 Codelab 방문 페이지에 나열되어 있습니다.
소개
대부분의 앱에는 사용자가 앱을 닫은 후에도 보관해야 하는 데이터가 있습니다. 예를 들어 앱은 재생목록, 게임 항목 인벤토리, 비용 및 소득 기록, 별자리 카탈로그, 시간 경과에 따른 수면 데이터를 저장할 수 있습니다. 일반적으로 영구 데이터를 저장하는 데 데이터베이스를 사용합니다.
Room
는 Android Jetpack의 일부인 데이터베이스 라이브러리로, Room
는 데이터베이스 설정 및 구성과 같은 여러 작업을 처리하고 앱이 일반적인 함수 호출을 사용하여 데이터베이스와 상호작용할 수 있도록 합니다. 내부적으로 Room
는 SQLite 데이터베이스 위에 있는 추상화 레이어입니다. Room
더 복잡한 쿼리의 쿼리 구문과 SQLite 모델을 따릅니다.
아래 이미지는 Room
데이터베이스가 이 과정에서 권장하는 전체 아키텍처에 어떻게 부합하는지 보여줍니다.
기본 요건
다음을 잘 알고 있어야 합니다.
- Android 앱의 기본 사용자 인터페이스 (UI) 빌드
- 활동, 프래그먼트, 뷰 사용
- 프래그먼트 간 이동과 Safe Args (Gradle 플러그인)를 사용하여 프래그먼트 간 데이터 전달
- 모델, 뷰 모델 팩토리,
LiveData
및 그 관찰자를 봅니다. 아키텍처 구성요소 주제는 이 과정의 이전 Codelab에서 다룹니다. - SQL 데이터베이스와 SQLite 언어의 기본사항 이해 간략한 개요 또는 복습은 SQLite Primer를 참고하세요.
학습할 내용
Room
데이터베이스를 만들고 상호작용하여 데이터를 유지하는 방법- 데이터베이스에서 테이블을 정의하는 데이터 클래스를 만드는 방법
- 데이터 액세스 객체(DAO)를 사용하여 Kotlin 함수를 SQL 쿼리에 매핑하는 방법
- 데이터베이스 작동 여부를 테스트하는 방법
실습할 내용
- 야간 수면 데이터 인터페이스가 포함된
Room
데이터베이스를 만듭니다. - 제공된 테스트를 사용하여 데이터베이스를 테스트합니다.
이 Codelab에서는 수면의 질을 추적하는 앱의 데이터베이스 부분을 빌드합니다. 앱은 데이터베이스를 사용하여 시간 경과에 따른 수면 데이터를 저장합니다.
앱에는 아래 그림과 같이 프래그먼트로 표시된 두 개의 화면이 있습니다.
왼쪽에 표시된 첫 번째 화면에는 추적을 시작하고 중지하는 버튼이 있습니다. 화면에 사용자의 모든 수면 데이터가 표시됩니다. 지우기 버튼은 앱에서 사용자에 대해 수집한 모든 데이터를 완전히 삭제합니다.
오른쪽에 표시된 두 번째 화면은 수면의 질 등급을 선택하기 위한 것입니다. 앱에서 평점은 숫자로 표시됩니다. 앱이 개발 목적으로 얼굴 아이콘과 동등한 얼굴을 모두 표시합니다.
사용자 플로우는 다음과 같습니다.
- 사용자가 앱을 열면 수면 추적 화면이 표시됩니다.
- 사용자가 시작 버튼을 탭합니다. 그러면 시작 시간이 기록되고 표시됩니다. 시작 버튼이 사용 중지되고 중지 버튼이 사용 설정됩니다.
- 사용자가 중지 버튼을 탭합니다. 이렇게 하면 종료 시간이 기록되고 수면의 질 화면이 열립니다.
- 사용자가 수면의 질 아이콘을 선택합니다. 화면이 닫히고 추적 화면에 수면 종료 시간과 수면의 질이 표시됩니다. Stop 버튼이 사용 중지되고 Start 버튼이 사용 설정됩니다. 이제 앱을 하루 사용할 준비가 되었습니다.
- 지우기 버튼은 데이터베이스에 데이터가 있을 때마다 사용 설정됩니다. 사용자가 지우기 버튼을 탭하면 거부 없이 모든 데이터가 삭제됩니다. 계속하시겠습니까?라는 메시지가 표시되지 않습니다.
이 앱은 전체 아키텍처의 컨텍스트에서 다음과 같이 단순화된 아키텍처를 사용합니다. 앱에서는 다음 구성요소만 사용합니다.
- UI 컨트롤러
- 모델 및
LiveData
보기 - Room 데이터베이스
1단계: 시작 앱 다운로드 및 실행하기
- GitHub에서 TrackMySleepQuality-Starter 앱을 다운로드합니다.
- 앱을 빌드하고 실행합니다. 앱은
SleepTrackerFragment
프래그먼트의 UI를 표시하지만 데이터는 표시하지 않습니다. 버튼은 탭에 응답하지 않습니다.
2단계: 시작 앱 검사
- Gradle 파일을 살펴보세요.
- 프로젝트 Gradle 파일
프로젝트 수준의build.gradle
파일에서 라이브러리 버전을 지정하는 변수를 확인합니다. 시작 앱에 사용된 버전은 원활하게 호환되며 이 앱에서 원활하게 작동합니다. 이 Codelab을 완료하면서 Android 스튜디오에서 일부 버전을 업데이트하라는 메시지가 표시될 수 있습니다. 앱에 포함된 버전을 업데이트할지 또는 유지할지 결정은 개발자에게 달려 있습니다. '범위' 컴파일 오류가 발생하면 최종 솔루션 앱에서 사용하는 라이브러리 버전의 조합을 사용해 보세요. - 모듈 Gradle 파일.
Room
및 코루틴의 종속 항목을 포함한 모든 Android Jetpack 라이브러리에 제공된 종속 항목을 확인합니다.
- 패키지 및 UI를 살펴보세요. 기능에 따라 앱이 구조화됩니다. 패키지에는 이 Codelab 시리즈 전반에 코드를 추가할 자리표시자 파일이 포함되어 있습니다.
database
패키지:Room
데이터베이스와 관련된 모든 코드sleepquality
및sleeptracker
패키지에는 각 화면의 프래그먼트, 뷰 모델, 뷰 모델 팩토리가 포함되어 있습니다.
- 수면의 질 데이터를 표시하는 데 도움이 되는 함수가 포함된
Util.kt
파일을 살펴보세요. 일부 코드는 나중에 만드는 뷰 모델을 참조하므로 주석 처리됩니다. - androidTest 폴더(
SleepDatabaseTest.kt
)를 살펴보세요. 이 테스트를 사용하여 데이터베이스가 의도한 대로 작동하는지 확인합니다.
Android에서는 데이터가 데이터 클래스로 표시되며, 함수 호출을 사용하여 데이터에 액세스하고 수정합니다. 그러나 데이터베이스 환경에서는 항목과 쿼리가 필요합니다.
- 항목은 데이터베이스에 저장할 객체 또는 개념과 그 속성을 나타냅니다. 항목 클래스는 테이블을 정의하고 클래스의 각 인스턴스는 테이블의 행을 나타냅니다. 각 속성은 열을 정의합니다. 앱에서 항목은 밤사이에 관한 정보를 보유합니다.
- 쿼리는 데이터베이스 표나 표 조합의 데이터나 정보 요청 또는 데이터 작업 실행 요청입니다. 일반적인 쿼리는 항목 가져오기, 삽입, 업데이트입니다. 예를 들어 기록된 모든 수면 시간을 쿼리하여 시작 시간을 기준으로 정렬할 수 있습니다.
Room
는 Kotlin 데이터 클래스에서 SQLite 테이블에 저장할 수 있는 항목으로, 함수 선언에서 SQL 쿼리로 가져오는 데 필요한 모든 작업을 실행합니다.
각 항목을 주석 처리된 데이터 클래스로, 상호작용을 주석 처리된 인터페이스인 데이터 액세스 객체 (DAO)로 정의해야 합니다. Room
는 주석 처리된 클래스를 사용하여 데이터베이스에서 테이블을 만들고 데이터베이스에서 작동하는 쿼리를 사용합니다.
1단계: SleepNight 항목 만들기
이 작업에서는 하룻밤의 수면을 주석 처리된 데이터 클래스로 정의합니다.
밤사이에 시작 시간, 종료 시간, 품질 평가를 기록해야 합니다.
밤을 고유하게 식별하려면 ID가 필요합니다.
database
패키지에서SleepNight.kt
파일을 찾아 엽니다.- ID, 시작 시간 (밀리초), 종료 시간 (밀리초) 및 숫자 수면의 질 평점을 위한 매개변수로
SleepNight
데이터 클래스를 만듭니다.
sleepQuality
를 초기화해야 하므로-1
으로 설정합니다. 이는 품질 데이터가 수집되지 않았음을 나타냅니다.- 종료 시간도 초기화해야 합니다. 아직 종료 시간이 기록되지 않았음을 알리는 시작 시간으로 설정합니다.
data class SleepNight(
var nightId: Long = 0L,
val startTimeMilli: Long = System.currentTimeMillis(),
var endTimeMilli: Long = startTimeMilli,
var sleepQuality: Int = -1
)
- 클래스 선언 앞에 데이터 클래스에
@Entity
주석을 답니다. 테이블 이름을daily_sleep_quality_table
로 지정합니다.tableName
의 인수는 선택사항이지만 사용하는 것이 좋습니다. 문서에서 다른 인수를 조회할 수 있습니다.
메시지가 표시되면androidx
라이브러리에서Entity
및 다른 모든 주석을 가져오세요.
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(...)
nightId
를 기본 키로 식별하려면nightId
속성에@PrimaryKey
주석을 답니다. 매개변수autoGenerate
를true
로 설정하여Room
에서 각 항목의 ID를 생성하도록 합니다. 이렇게 하면 각 밤의 ID가 고유해집니다.
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,...
- 나머지 속성에
@ColumnInfo
주석을 답니다. 아래와 같이 매개변수를 사용하여 속성 이름을 맞춤설정합니다.
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "daily_sleep_quality_table")
data class SleepNight(
@PrimaryKey(autoGenerate = true)
var nightId: Long = 0L,
@ColumnInfo(name = "start_time_milli")
val startTimeMilli: Long = System.currentTimeMillis(),
@ColumnInfo(name = "end_time_milli")
var endTimeMilli: Long = startTimeMilli,
@ColumnInfo(name = "quality_rating")
var sleepQuality: Int = -1
)
- 코드를 빌드하고 실행하여 오류가 없는지 확인합니다.
이 작업에서는 데이터 액세스 객체 (DAO)를 정의합니다. Android에서 DAO는 데이터베이스를 삽입하고 삭제하며 업데이트하기 위한 편의 메서드를 제공합니다.
Room
데이터베이스를 사용하는 경우 코드에서 Kotlin 함수를 정의하고 호출하여 데이터베이스를 쿼리합니다. 이러한 Kotlin 함수는 SQL 쿼리에 매핑됩니다. 주석을 사용하여 DAO에서 이러한 매핑을 정의하며 Room
은 필요한 코드를 만듭니다.
데이터베이스 액세스를 위한 맞춤 인터페이스를 정의하는 것을 DAO라고 생각하세요.
일반적인 데이터베이스 작업의 경우 Room
라이브러리는 @Insert
, @Delete
, @Update
와 같은 편의 주석을 제공합니다. 그 외 모든 경우에는 @Query
주석이 있습니다. SQLite에서 지원하는 모든 쿼리를 작성할 수 있습니다.
또한 Android 스튜디오에서 쿼리를 만들 때 컴파일러가 SQL 쿼리에서 구문 오류를 검사합니다.
수면 추적 데이터베이스는 다음과 같이 할 수 있습니다.
- 새 밤에 삽입합니다.
- 기존 밤을 업데이트하여 종료 시간과 품질 등급을 업데이트합니다.
- 키에 따라 특정 밤을 가져옵니다.
- 모든 밤을 수신하여 표시할 수 있습니다.
- 최근 수면 확인하기
- 데이터베이스의 모든 항목을 삭제합니다.
1단계: SleepDatabase DAO 만들기
database
패키지에서SleepDatabaseDao.kt
를 엽니다.interface
SleepDatabaseDao
에는@Dao
주석이 추가됩니다. 모든 DAO에는@Dao
키워드로 주석을 달아야 합니다.
@Dao
interface SleepDatabaseDao {}
- 인터페이스 본문에
@Insert
주석을 추가합니다.@Insert
아래에서Entity
클래스SleepNight
의 인스턴스를 인수로 사용하는insert()
함수를 추가합니다.
정답입니다.Room
은SleepNight
을 데이터베이스에 삽입하는 데 필요한 모든 코드를 생성합니다. Kotlin 코드에서insert()
를 호출하면Room
은 SQL 쿼리를 실행하여 데이터베이스에 항목을 삽입합니다. 참고: 원하는 모든 함수를 호출할 수 있습니다.
@Insert
fun insert(night: SleepNight)
- 한
SleepNight
에update()
함수와 함께@Update
주석을 추가합니다. 업데이트된 항목은 전달된 항목과 같은 키를 가진 항목입니다. 항목의 다른 속성 일부나 전부를 업데이트할 수 있습니다.
@Update
fun update(night: SleepNight)
나머지 기능에는 편의 주석이 없으므로 @Query
주석을 사용하여 SQLite 쿼리를 제공해야 합니다.
Long
key
인수를 사용하고 null을 허용하는SleepNight
를 반환하는get()
함수와 함께@Query
주석을 추가합니다. 누락된 매개변수에 대한 오류가 표시됩니다.
@Query
fun get(key: Long): SleepNight?
- 쿼리는 주석에 문자열 매개변수로 제공됩니다.
@Query
에 매개변수를 추가합니다. 이 클래스를 SQLite 쿼리인String
로 만듭니다.
daily_sleep_quality_table
에서 모든 열을 선택합니다.WHERE
nightId
는 :key
인수와 일치합니다.:key
에 주목하세요. 쿼리에서 콜론 표기법을 사용하여 함수의 인수를 참조합니다.
("SELECT * from daily_sleep_quality_table WHERE nightId = :key")
clear()
함수와 SQLite 쿼리를 사용하여 다른@Query
를daily_sleep_quality_table
의 모든DELETE
에 추가합니다. 이 쿼리는 테이블 자체를 삭제하지 않습니다.@Delete
주석은 한 항목을 삭제합니다.@Delete
를 사용하여 삭제할 밤 목록을 제공할 수 있습니다. 단점은 표에서 무엇을 가져오거나 알아야 하는지 알아야 한다는 것입니다.@Delete
주석은 특정 항목을 삭제하는 데 적합하지만 테이블의 모든 항목을 삭제하는 데 효율적이지 않습니다.
@Query("DELETE FROM daily_sleep_quality_table")
fun clear()
getTonight()
함수와 함께@Query
를 추가합니다. 함수가 비어 있는 경우를 함수가 처리할 수 있도록getTonight()
에서 반환된SleepNight
를 null 허용 여부로 설정합니다. (표는 처음부터 비어 있고 데이터가 삭제된 후 비어 있습니다.)
데이터베이스에서 "tonight"를 가져오려면nightId
순으로 정렬된 결과 목록의 첫 번째 요소를 내림차순으로 반환하는 SQLite 쿼리를 작성합니다.LIMIT 1
를 사용하여 하나의 요소만 반환합니다.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC LIMIT 1")
fun getTonight(): SleepNight?
getAllNights()
함수와 함께@Query
를 추가합니다.
- SQLite 쿼리가
daily_sleep_quality_table
의 모든 열을 내림차순으로 반환하도록 합니다. getAllNights()
가SleepNight
항목의 목록을LiveData
로 반환하도록 합니다.Room
은 이LiveData
를 자동으로 업데이트하므로 명시적으로 한 번만 데이터를 가져오면 됩니다.androidx.lifecycle.LiveData
에서LiveData
를 가져와야 할 수도 있습니다.
@Query("SELECT * FROM daily_sleep_quality_table ORDER BY nightId DESC")
fun getAllNights(): LiveData<List<SleepNight>>
- 눈에 띄는 변경사항은 표시되지 않지만 앱을 실행하여 오류가 없는지 확인합니다.
이 작업에서는 이전 작업에서 만든 Entity
와 DAO를 사용하는 Room
데이터베이스를 만듭니다.
@Database
주석이 달린 추상 데이터베이스 홀더 클래스를 만들어야 합니다. 이 클래스에는 데이터베이스가 없으면 데이터베이스 인스턴스를 만들거나 기존 데이터베이스에 대한 참조를 반환하는 메서드가 하나 있습니다.
Room
데이터베이스를 가져오는 작업은 약간 복잡하므로 코드로 시작하기 전에 일반적인 프로세스는 다음과 같습니다.
extends RoomDatabase
의public abstract
클래스를 만듭니다. 이 클래스는 데이터베이스 홀더 역할을 합니다. 이 클래스는 추상 클래스입니다.Room
이 구현을 만들기 때문입니다.- 클래스에
@Database
주석을 답니다. 인수에서 데이터베이스의 항목을 선언하고 버전 번호를 설정합니다. companion
객체 내에서SleepDatabaseDao
를 반환하는 추상 메서드나 속성을 정의합니다.Room
은 본문을 생성합니다.- 전체 앱에
Room
데이터베이스 인스턴스가 하나만 필요하므로RoomDatabase
를 싱글톤으로 만듭니다. Room
의 데이터베이스 빌더를 사용하여 데이터베이스가 없는 경우에만 데이터베이스를 만드세요. 있다면 기존 데이터베이스를 반환합니다.
1단계: 데이터베이스 만들기
database
패키지에서SleepDatabase.kt
를 엽니다.- 파일에서
RoomDatabase
를 확장하는SleepDatabase
이라는abstract
클래스를 만듭니다.
이 클래스에@Database
주석을 답니다.
@Database()
abstract class SleepDatabase : RoomDatabase() {}
- 누락된 항목 및 버전 매개변수에 대한 오류가 표시됩니다.
@Database
주석에는Room
이 데이터베이스를 빌드할 수 있도록 인수가 여러 개 필요합니다.
SleepNight
을entities
목록이 있는 유일한 항목으로 제공합니다.version
를1
로 설정합니다. 스키마를 변경할 때마다 버전 번호를 높여야 합니다.- 스키마 버전 기록 백업을 유지하지 않도록
exportSchema
를false
로 설정합니다.
entities = [SleepNight::class], version = 1, exportSchema = false
- 데이터베이스는 DAO를 알아야 합니다. 클래스 본문 내에서
SleepDatabaseDao
를 반환하는 추상 값을 선언합니다. DAO는 여러 개가 있을 수 있습니다.
abstract val sleepDatabaseDao: SleepDatabaseDao
- 바로 아래에
companion
객체를 정의합니다. 동반 객체를 사용하면 클라이언트가 클래스를 인스턴스화하지 않고 데이터베이스를 만들거나 가져오는 메서드에 액세스할 수 있습니다. 이 클래스의 유일한 목적이 데이터베이스를 제공하는 것이기 때문에 데이터베이스를 인스턴스화할 이유가 없습니다.
companion object {}
companion
객체 내에서 데이터베이스에 관한 null을 허용하는 비공개 변수INSTANCE
를 선언하고null
로 초기화합니다.INSTANCE
변수는 데이터베이스가 만들어지면 데이터베이스 참조를 유지합니다. 이렇게 하면 데이터베이스에 대한 연결을 반복적으로 여는 것을 방지할 수 있으며, 이는 비용이 많이 듭니다.
@Volatile
에 INSTANCE
주석을 답니다. 휘발성 변수의 값은 캐시되지 않고 모든 쓰기와 읽기는 기본 메모리에서 실행됩니다. 이렇게 하면 INSTANCE
값이 항상 최신 상태로 유지되고 모든 실행 스레드와 동일하게 유지됩니다. 즉, 한 스레드에서 INSTANCE
를 변경하면 다른 모든 스레드에 즉시 표시되며, 두 스레드가 각각 캐시의 동일한 항목을 업데이트하므로 문제가 발생하는 상황은 발생하지 않습니다.
@Volatile
private var INSTANCE: SleepDatabase? = null
INSTANCE
아래에서(여전히companion
객체 내) 데이터베이스 빌더에 필요한Context
매개변수를 사용하여getInstance()
메서드를 정의합니다.SleepDatabase
유형을 반환합니다.getInstance()
에서 아직 아무것도 반환하지 않아 오류가 표시됩니다.
fun getInstance(context: Context): SleepDatabase {}
getInstance()
내부에synchronized{}
블록을 추가합니다. 컨텍스트에 액세스할 수 있도록this
를 전달합니다.
여러 스레드가 동시에 데이터베이스 인스턴스를 요청하여 하나가 아닌 두 개의 데이터베이스가 생성될 수 있습니다. 이 문제는 이 샘플 앱에서 발생할 가능성이 없지만 더 복잡한 앱에서는 발생할 수 있습니다. 코드를 래핑하여 데이터베이스를synchronized
로 래핑하면 한 번에 한 실행 스레드만 이 코드 블록에 들어갈 수 있으므로 데이터베이스가 한 번만 초기화됩니다.
synchronized(this) {}
- 동기화된 블록 내에서
INSTANCE
의 현재 값을 로컬 변수instance
에 복사합니다. 이는 로컬 변수에서만 사용할 수 있는 스마트 변환을 활용합니다.
var instance = INSTANCE
synchronized
블록 내synchronized
블록 끝에 있는return instance
반환 유형 불일치 오류를 무시합니다. 완료한 후에는 null을 반환하지 않습니다.
return instance
return
문 위에if
문을 추가하여instance
가 null인지, 즉 아직 데이터베이스가 없는지 확인합니다.
if (instance == null) {}
instance
가null
이면 데이터베이스 빌더를 사용하여 데이터베이스를 가져옵니다.if
문의 본문에서Room.databaseBuilder
를 호출하고 전달한 컨텍스트, 데이터베이스 클래스, 데이터베이스 이름sleep_history_database
를 제공합니다. 오류를 삭제하려면 다음 단계에서 이전 전략과build()
를 추가해야 합니다.
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database")
- 필요한 이전 전략을 빌더에 추가합니다.
.fallbackToDestructiveMigration()
를 사용합니다.
일반적으로 스키마 변경 시점에 관한 이전 전략과 함께 이전 객체를 제공해야 합니다. 이전 객체는 데이터가 손실되지 않도록 이전 스키마의 모든 행을 가져와 새 스키마의 행으로 변환하는 방법을 정의하는 객체입니다. 이전은 이 Codelab의 범위를 벗어납니다. 간단한 해결 방법은 데이터베이스를 제거했다가 다시 빌드하는 것입니다. 즉, 데이터가 손실됩니다.
.fallbackToDestructiveMigration()
- 마지막으로
.build()
를 호출합니다.
.build()
if
문 내의 마지막 단계로INSTANCE = instance
를 할당합니다.
INSTANCE = instance
- 최종 코드는 다음과 같이 표시됩니다.
@Database(entities = [SleepNight::class], version = 1, exportSchema = false)
abstract class SleepDatabase : RoomDatabase() {
abstract val sleepDatabaseDao: SleepDatabaseDao
companion object {
@Volatile
private var INSTANCE: SleepDatabase? = null
fun getInstance(context: Context): SleepDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
SleepDatabase::class.java,
"sleep_history_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
}
return instance
}
}
}
}
- 코드를 빌드하고 실행합니다.
이제 Room
데이터베이스 작업을 위한 모든 기본 요소를 완료했습니다. 이 코드는 컴파일되고 실행되지만 실제로 작동하는지는 알 수 없습니다. 따라서 기본적인 테스트를 추가하는 것이 좋습니다.
2단계: SleepDatabase 테스트
이 단계에서는 제공된 테스트를 실행하여 데이터베이스가 작동하는지 확인합니다. 그러면 데이터베이스를 구축하기 전에 데이터베이스가 작동합니다. 제공된 테스트는 기본적인 테스트입니다. 프로덕션 앱의 경우 모든 DAO의 모든 함수와 쿼리를 실행합니다.
시작 앱에는 androidTest 폴더가 있습니다. 이 androidTest 폴더에는 Android 계측과 관련된 단위 테스트가 포함되어 있는데, 이는 테스트에 Android 프레임워크가 필요하다는 의미입니다. 따라서 실제 또는 가상 기기에서 테스트를 실행해야 한다는 의미입니다. 물론 Android 프레임워크와 관련이 없는 순수 단위 테스트를 만들고 실행할 수도 있습니다.
- Android 스튜디오의 androidTest 폴더에서 SleepDatabaseTest 파일을 엽니다.
- 코드의 주석 처리를 삭제하려면 주석 처리된 코드를 모두 선택하고
Cmd+/
또는Control+/
단축키를 누릅니다. - 파일을 살펴보세요.
여기에서 재사용할 수 있는 또 다른 코드이므로 테스트 코드를 빠르게 살펴보겠습니다.
SleepDabaseTest
는 테스트 클래스입니다.@RunWith
주석은 테스트를 설정하고 실행하는 프로그램인 테스트 실행기를 식별합니다.- 설정 중에는
@Before
주석이 달린 함수가 실행되고SleepDatabaseDao
를 사용하여 메모리 내SleepDatabase
를 만듭니다. '메모리 내'는 이 데이터베이스가 파일 시스템에 저장되지 않고 테스트가 실행된 후에 삭제된다는 의미입니다. - 또한 메모리 내 데이터베이스를 빌드할 때 이 코드는 다른 테스트별 메서드인
allowMainThreadQueries
를 호출합니다. 기본적으로 기본 스레드에서 쿼리를 실행하려고 하면 오류가 발생합니다. 이 메서드를 사용하면 기본 스레드에서 테스트를 실행할 수 있으며 테스트 중에만 해야 합니다. @Test
주석이 달린 테스트 메서드에서SleepNight
를 만들고 삽입하고 검색하여 동일한 것으로 어설션합니다. 문제가 발생하면 예외가 발생합니다. 실제 테스트에는 여러@Test
메서드가 있습니다.- 테스트가 완료되면
@After
주석이 달린 함수가 실행되어 데이터베이스를 닫습니다.
- Project 창에서 테스트 파일을 마우스 오른쪽 버튼으로 클릭하고 Run 'SleepDatabaseTest'를 선택합니다.
- 테스트가 실행된 후 SleepDatabaseTest 창에서 모든 테스트가 통과했는지 확인합니다.
모든 테스트를 통과했으므로 이제 다음과 같은 몇 가지 사항을 알게 되었습니다.
- 데이터베이스가 올바르게 생성됩니다.
SleepNight
를 데이터베이스에 삽입할 수 있습니다.SleepNight
를 다시 가져올 수 있습니다.SleepNight
의 품질 값이 올바르게 지정되었습니다.
Android 스튜디오 프로젝트: TrackMySleepQualityRoomAndTesting
데이터베이스를 테스트할 때 DAO에 정의된 모든 메서드를 실행해야 합니다. 테스트를 완료하려면 테스트를 추가하고 실행하여 다른 DAO 메서드를 실행합니다.
- 테이블을
@Entity
주석이 달린 데이터 클래스로 정의합니다.@ColumnInfo
주석이 달린 속성을 테이블의 열로 정의합니다. - 데이터 액세스 객체(DAO)를
@Dao
주석이 달린 인터페이스로 정의합니다. DAO는 Kotlin 함수를 데이터베이스 쿼리에 매핑합니다. - 주석을 사용하여
@Insert
,@Delete
,@Update
함수를 정의합니다. - SQLite 쿼리 문자열과 함께
@Query
주석을 다른 쿼리의 매개변수로 사용합니다. - 데이터베이스를 반환하는
getInstance()
함수가 있는 추상 클래스를 만듭니다. - 계측 테스트를 사용하여 데이터베이스와 DAO가 예상대로 작동하는지 테스트합니다. 제공된 테스트를 템플릿으로 사용할 수 있습니다.
Udacity 과정:
Android 개발자 문서:
RoomDatabase
Database
(주석)Room
와 함께 원시 쿼리를 사용할 수 있습니다.Roomdatabase.Builder
- 테스트 교육
SQLiteDatabase
클래스Dao
Room
지속성 라이브러리
기타 문서 및 도움말:
- 싱글톤 패턴
- Google Developers Experts: 휘발성 데이터 및 동기화 사용 예시
- 컴패니언 객체
- Room을 사용하는 이전 이해
- Room 이전 테스트
- 데이터베이스 기록
- SQLite 웹사이트
- SQLite에서 이해하는 SQL의 전체 설명
이 섹션에는 강사가 진행하는 과정의 일부로 이 Codelab을 통해 작업하는 학생들의 숙제 과제가 나와 있습니다. 강사는 다음을 처리합니다.
- 필요한 경우 과제를 할당합니다.
- 학생에게 과제 과제를 제출하는 방법을 알려주세요.
- 과제 과제를 채점합니다.
강사는 이러한 추천을 원하는 만큼 사용할 수 있으며 다른 적절한 숙제를 할당해도 좋습니다.
이 Codelab을 직접 학습하고 있다면 언제든지 숙제를 통해 지식을 확인해 보세요.
답변
질문 1
클래스가 Room
데이터베이스에 저장할 항목을 나타내는지 어떻게 나타내나요?
- 클래스가
DatabaseEntity
을 확장하도록 설정합니다. - 클래스에
@Entity
주석을 답니다. - 클래스에
@Database
주석을 답니다. - 클래스를
RoomEntity
로 확장하고 클래스에@Room
주석을 추가합니다.
질문 2
DAO (데이터 액세스 객체)는 Room
에서 Kotlin 함수를 데이터베이스 쿼리에 매핑하는 데 사용하는 인터페이스입니다.
인터페이스가 Room
데이터베이스의 DAO를 나타내도록 표시하려면 어떻게 해야 하나요?
- 인터페이스가
RoomDAO
을 확장합니다. - 인터페이스에서
EntityDao
를 확장한 후DaoConnection()
메서드를 구현합니다. - 인터페이스에
@Dao
주석을 답니다. - 인터페이스에
@RoomConnection
주석을 답니다.
질문 3
다음 중 Room
데이터베이스에 관한 올바른 설명은 무엇인가요? 해당 항목을 모두 선택하세요.
Room
데이터베이스의 테이블을 주석 처리된 데이터 클래스로 정의할 수 있습니다.- 쿼리에서
LiveData
를 반환하면LiveData
가 변경되면Room
에서LiveData
를 업데이트된 상태로 유지합니다. - 각
Room
데이터베이스에는 DAO가 하나만 있어야 합니다. - 클래스를
Room
데이터베이스로 식별하려면RoomDatabase
의 서브클래스로 만들고@Database
주석을 추가합니다.
질문 4
다음 중 @Dao
인터페이스에서 사용할 수 있는 주석은 무엇인가요? 해당 항목을 모두 선택하세요.
@Get
@Update
@Insert
@Query
질문 5
데이터베이스가 작동하는지 확인하려면 어떻게 해야 하나요? 해당하는 보기를 모두 선택하세요.
- 계측 테스트를 작성합니다.
- 데이터가 표시될 때까지 앱을 계속 작성하고 실행합니다.
- DAO 인터페이스의 메서드 호출을
Entity
클래스의 동등한 메서드 호출로 바꿉니다. Room
라이브러리에서 제공하는verifyDatabase()
함수를 실행합니다.
다음 강의 시작:
이 과정의 다른 Codelab 링크는 Android Kotlin 기초 Codelab 방문 페이지를 참고하세요.