Android

(Android / Kotlin) - Room 을 사용한 데이터 유지

돗개진 2024. 8. 16. 12:45

[ Room ]

- SQLite를 쉽게 사용할 수 있는 데이터베이스 객체 매핑 라이브러리

- 쉽게 Query를 사용할 수 있는 API 를 제공함

- Query 를 컴파일 시간에 검증함

- Query 결과를 LiveData 로 하여 데이터베이스가 변경될 때마다 쉽게 UI를 변경할 수 있음

=> SQLite 보다 Room 을 사용할 것을 권장

 

 

[ Room 주요 3 요소 ]

@Database

클래스를 데이터베이스로 지정하는 annotation, RoomDatabase를 상속받은 클래스여야 함

 

@Entity

클래스를 테이블 스키마로 지정하는 annotation

 

@Dao

클래스를 DAO(Data Access Object)로 지정하는 annotation

-> 기본적인 insert, delete, update SQL은 자동으로 만들어 줌, 복잡한 SQL 은 직접 만들 수 있음

 

 

[ gradle 파일 설정 ]

- Room 은 안드로이드 아키텍처에 포함되어 있음

- 사용하기 위해 build.gradle 파일의 dependecies 에 내용을 추가해야 함

plugins {
    alias(libs.plugins.androidApplication)
    alias(libs.plugins.jetbrainsKotlinAndroid)
    kotlin("kapt")
}

ㄴ> kapt 를 사용하기 위해 plugins 에 관련 내용을 추가해야 함 (버전을 명시해도 되지만 현재 본인이 사용해야 하는 Kotlin 버전에 맞춰서 명시해 줘야 함)

 

dependencies {

    val room_version = "2.6.1"

    implementation("androidx.room:room-runtime:$room_version")
    annotationProcessor("androidx.room:room-compiler:$room_version")
    kapt("androidx.room:room-compiler:$room_version")
    implementation("androidx.room:room-ktx:$room_version")
    testImplementation("androidx.room:room-testing:$room_version")

}

ㄴ> 의존성 추가 부분에는 사용할 room 의 버전 (가능한 최신 버전을 쓰는 것이 좋음) 의 내용과 필요한 다른 것들을 추가하면 된다

 


 

[ Entity 생성 ]

- 테이블 스키마 정의

- CREATE TABLE student_table (student_id INTEGER PRIMARY KEY, name TEXT NOT NULL);

- @Entity data class Student

package com.example.roomdatabase.data

import androidx.room.*

@Entity(tableName = "student_table")    // 테이블 이름을 student_table로 지정함
data class Student (
    @PrimaryKey @ColumnInfo(name = "student_id")
    val id: Int,
    val name: String
)

 

 

 

[ DAO 생성 ]

- DAO 는 interfaceabstract class 로 정의되어야 함

- Annotation 에 SQL 쿼리를 정의하고 그 쿼리를 위한 메소드를 선언

- 가능한 annotation 으로 @Insert, @Update, @Delete, @Query 가 있음

 

@Dao
interface MyDAO {
    @Insert(onConflict = OnConflictStrategy.REPLACE)  // INSERT, key 충돌이 나면 새 데이터로 교체
    suspend fun insertStudent(student: Student)

    @Query("SELECT * FROM student_table")
    fun getAllStudents(): LiveData<List<Student>>        // LiveData<> 사용

    @Query("SELECT * FROM student_table WHERE name = :sname")   
    suspend fun getStudentByName(sname: String): List<Student>

    @Delete
    suspend fun deleteStudent(student: Student); // primary key is used to find the student

    // ...
}

 

  • @Insert, @Update, @Delete는 SQL 쿼리를 작성하지 않아도 컴파일러가 자동으로 생성함
    • @Insert나 @Update는 key가 중복되는 경우 처리를 위해 onConflict를 지정할 수 있음
      • OnConflictStrategy.ABORT: key 충돌시 종료
      • OnConflictStrategy.IGNORE: key 충돌 무시
      • OnConflictStrategy.REPLACE: key 충돌시 새로운 데이터로 변경
    • @Update나 @Delete는 primary key에 해당되는 튜플을 찾아서 변경/삭제 함

 

 

 

[ Migration ]

 

앞에서 MyRoomDatabase 객체 생성 후 addMigrations() 메소드를 호출하여 Miagration 방법을 지정함

Room.databaseBuilder(...).addMigrations(MIGRATION_1_2, MIGRATION_2_3)

private val MIGRATION_1_2 = object : Migration(1, 2) {   // version 1 -> 2
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE student_table ADD COLUMN last_update INTEGER")
    }
}

private val MIGRATION_2_3 = object : Migration(2, 3) {   // version 2 -> 3
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE class_table ADD COLUMN last_update INTEGER")
    }
}

ㄴ> 여러 개의 Migration 을 지정할 수 있다.

 

 

 

[ UI와 연결 ]

 

myDao = MyDatabase.getDatabase(this).getMyDao()
runBlocking { // (주의) UI를 블록할 수 있는 DAO 메소드를 UI 스레드에서 바로 호출하면 안됨
    myDao.insertStudent(Student(1, "james"))  // suspend 지정되어 있음
}
val allStudents = myDao.getAllStudents() // LiveData는 Observer를 통해 비동기적으로 데이터를 가져옴

 

 

[ LiveData ]

안드로이드 아키텍처 컴포넌트의 일부로 관찰 가능한 데이터 홀더 클래스이며 이를 통해 UI 컴포넌트(ex: 액티비티, 프래그먼트)는 데이터의 변경 사항을 관찰하고 이에 반응함. 데이터가 변경될 때마다 LiveData 는 관찰자에게 알림을 보냄

 

LiveData의 핵심 특징

- 수명 주기 인식

: 안드로이드의 수명주기를 인식함 액티비티나 프래금먼트의 수명 주기

 

https://github.com/Yejin-Byun/RoomDataBase.git

 

GitHub - Yejin-Byun/RoomDataBase

Contribute to Yejin-Byun/RoomDataBase development by creating an account on GitHub.

github.com