[Android] Room
아래 내용은 Android Developer 공식 문서 내용을 참고하여 작성한 자습 기록입니다.
📚Android 정리 - Room
📔Room이란
Room은 SQLite의 전체 기능을 활용하면서 보다 강력한 데이터베이스 액세스를 허용하기 위해 SQLite에 대한 추상화 계층을 제공하는 라이브러리이다. Room은
- 더 나은 컴파일 시간
- 향상된 테스트
- 더 쉬운 데이터 마이그레이션 처리
등 기존 SQLite 데이터베이스 액세스에 비해 많은 이점을 제공한다.
기존 SQLite를 활용해서도 데이터베이스 작업을 처리할 수 있지만 아래와 같은 이유로 Room 라이브러리 사용이 권장된다.
📔Room 구성요소
📖 Entity
데이터베이스의 테이블을 가리킨다. Entity는 테이블의 구조와 테이블의 열을 정의한다.
📖 DAO(Data Access Object)
데이터베이스에서 데이터를 읽고 쓰기 위한 API를 제공한다. 다시 말해, 데이터 삽입, 업데이트 및 검색과 같은 데이터베이스 작업에 해당하는 메서드를 정의한다.
📖 Database
데이터베이스에 대한 기본 액세스 포인트 역할을 한다. Entity와 DAO를 포함하며 기본 SQLite 데이터베이스 생성 및 관리를 담당한다.
📔Room 사용해보기
Room을 사용하기 위해서 성과 이름을 입력한 뒤 버튼을 누르면, 이름이 데이터베이스에 추가되도록 간단하게 구현해 보았다.
📖 라이브러리 추가
Room 라이브러리를 추가하기 위해 아래 항목들을 build.gradle에 추가해 준다.
val room_version = "2.5.0"
implementation("androidx.room:room-runtime:$room_version")
annotationProcessor("androidx.room:room-compiler:$room_version")
📖 UI 구현
UI는 간단하게 EditText 2개와 Button 1개로 구성해 주었다.
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="32dp"
tools:context=".MainActivity">
<TextView
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="정보"
android:textSize="34sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/firstNameTextInputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/titleTextView">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/firstNameTextInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="성" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/lastNameTextInputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="@id/firstNameTextInputLayout"
app:layout_constraintStart_toStartOf="@id/firstNameTextInputLayout"
app:layout_constraintTop_toBottomOf="@id/firstNameTextInputLayout">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/lastNameTextInputEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="이름" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="@+id/addButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="확인"
app:layout_constraintEnd_toEndOf="@id/firstNameTextInputLayout"
app:layout_constraintStart_toStartOf="@id/firstNameTextInputLayout"
app:layout_constraintTop_toBottomOf="@id/lastNameTextInputLayout" />
</androidx.constraintlayout.widget.ConstraintLayout>
📖 Entity - User.kt
테이블을 가리키는 Entity 클래스를 정의한다. 각각의 User 인스턴스는 user 테이블의 행 하나를 나타낸다.
@Entity(tableName = "user_table")
data class User(
@ColumnInfo(name = "first_name") val firstName: String,
@ColumnInfo(name = "last_name") val lastName: String,
@PrimaryKey(autoGenerate = true) val uid: Int = 0,
)
- @Entity 주석은 해당 Entity 클래스의 데이터가 저장될 데이터베이스의 테이블 이름을 정의하는 데 사용된다. 매개변수인
tableName
으로 테이블의 이름을 변경할 수 있고 기본적으로 클래스 이름이 테이블의 이름이 된다. - data class 내의 속성들은 테이블의 컬럼명이 된다. 컬럼명을 변경하고자 한다면, @ColumnInfo 주석을 추가한 뒤 매개변수 name에 이름을 지정해주면 된다.
- @PrimaryKey 주석은 테이블의 primary key를 정의하기 위해 사용된다. autoGenerate 파라미터의 값으로 true를 지정할 시, primary key의 값이 Room 라이브러리에 의해 자동으로 생성된다.
📖 Dao - UserDao.kt
Dao 인터페이스에서 SQL 쿼리를 메소드와 연결해 호출할 수 있도록 한다.
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
@Insert
fun insertUser(user: User)
@Query("DELETE FROM user")
fun deleteAll()
}
- @Dao 주석으로 해당 인터페이스가 Dao 임을 명시한다
- Entity 테이블의 모든 데이터를 검색할 수 있는 쿼리를 작성해 주었고 이를 @Query 주석의 인자로 넣어준 뒤, 메서드와 연결해 준다
- @Insert 데이터를 테이블에 추가하는 주석으로 추가적인 쿼리문을 작성하지 않아도 자동으로 추가될 수 있도록 지원해 준다.
📖 AppDatabase
@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
- @Database 주석은 해당 클래스가 Room 데이터베이스임을 나타낸다. entities 매개변수에 Entity 클래스들을 지정하고, version 매개변수는 데이터베이스의 버전을 정의한다
- 추상 클래스로 정의해야 하고, 내부의 추상 메서드로 Dao에 접근할 수 있도록 한다
📖 MainActivity.kt
이제 데이터베이스 생성을 위한 준비를 모두 마무리했으므로 생성하면 된다. onCreate() 내부에 db를 생성하고 이후 데이터를 처리할 경우 메인 스레드가 아닌 작업 스레드에서 실행하도록 한다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val db =
Room.databaseBuilder(
applicationContext,
AppDatabase::class.java,
"userDB"
).build()
val firstNameEditText = findViewById<EditText>(R.id.firstNameTextInputEditText)
val lastNameEditText = findViewById<EditText>(R.id.lastNameTextInputEditText)
val addButton = findViewById<Button>(R.id.addButton)
addButton.setOnClickListener {
Thread {
val firstName = firstNameEditText.text.toString()
val lastName = lastNameEditText.text.toString()
db.userDao().insertUser(User(firstName, lastName))
runOnUiThread {
firstNameEditText.setText("")
lastNameEditText.setText("")
}
}.start()
}
}
}