[Android] Android Jetpack - Room

알린·2024년 2월 19일
0

Android

목록 보기
7/21

Room

  • Room이란?
    • Android JetPack 라이브러리의 AAC(Android Architecture Component) 중 하나
    • SQLite를 활용해서 기기 자체의 내부 저장소(로컬 데이터베이스)에 접근하는 방식
    • 기기가 네트워크에 엑세스할 수 없는 오프라인 상태에서도 콘텐츠를 탐색할 수 있으며 다시 기기가 온라인 상태가 되면 변경사항이 DB에 동기화
  • SQLite 대신 Room의 사용을 권장하는 이유
    • SQL 쿼리의 컴파일 시간 확인 가능
    • 반복적이고 오류가 발생하기 쉬운 상용구 코드를 최소화하는 편의 주석
    • 간소화된 데이터베이스 이전 경로
  • 👉 Room 데이터베이스 구현 관련 포스팅 참고


  1. 프로젝트 수준 build.gradle에 다음 코드 추가
    👉 KSP 플러그인 추가 공식 문서(버전 참고)
id("com.google.devtools.ksp") version "1.9.22-1.0.17" apply false
  1. 모듈 수준 build.gradle의 plugin에 다음 코드 추가
id("com.google.devtools.ksp")
  1. 모듈 수준 build.gradle에 다음 중 필요한 의존성 추가
    👉 Room 의존성 추가 공식 문서(버전 참고)
dependencies {
    val room_version = "2.6.1"

    implementation("androidx.room:room-runtime:$room_version")
    annotationProcessor("androidx.room:room-compiler:$room_version")
    
    // To use Kotlin Symbol Processing (KSP)
    ksp("androidx.room:room-compiler:$room_version")

    // optional - Kotlin Extensions and Coroutines support for Room
    implementation("androidx.room:room-ktx:$room_version")

    // optional - Guava support for Room, including Optional and ListenableFuture
    implementation("androidx.room:room-guava:$room_version")

    // optional - Test helpers
    testImplementation("androidx.room:room-testing:$room_version")

    // optional - Paging 3 Integration
    implementation("androidx.room:room-paging:$room_version")
}
  1. data class 생성해 다음 Entity 코드 작성
  • Entity
    • 데이터베이스 테이블 정보를 클래스로 표현한 것
    • @ColumnInfo: 테이블의 칼럼으로 설정할 변수 선언 시 명시할 어노테이션
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity(tableName = "UserInfo")
data class UserEntity(
    @PrimaryKey(autoGenerate = true)  // id가 자동으로 1씩 증가되며 저장
    val id: Long = 0L,
    @ColumnInfo(name = "name")
    val name: String,
    @ColumnInfo(name = "email")
    val email: String,
    @ColumnInfo(name = "password")
    val password: String
)
  1. Interface 생성해 다음 DAO 코드 작성
  • DAO
    • 데이터베이스에 직접 접근하지 않고 DAO 객체를 생성해 데이터로 무엇을 할지 정의
    • 인터페이스 상단에 @Dao 어노테이션 명시(Dao 인터페이스에서 테이블에 접근할 CRUD 메소드(Create, Read, Update, Delete)를 @Insert, @Query, @Update, @Delete 어노테이션을 사용해 정의)
      • @Query : SQL 질의문을 통해 데이터베이스에 접근
      • @Insert : 데이터베이스에 추가
        (onConflict 속성은 칼럼이 충돌할 경우 어떻게 처리할지에 관한 속성)
      • @Update : 데이터베이스 내용 갱신
      • @Delete : 데이터베이스 내용 삭제
  • 회원 등록과 삭제는 시간이 걸리는 작업이므로 코루틴 안에서 비동기적으로 수행하기 위해 앞에 suspend를 붙여줌
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Query

@Dao
interface LoginDAO {
    @Query("select * from UserInfo")
    fun getEmailList(): List<UserEntity>  // 등록된 회원인지 확인

    @Query("select password from userinfo where email = :email")
    fun getPasswordByEmail(email: String): String  // 이메일에 따른 비밀번호 반환

    @Insert
    suspend fun insertUser(userInfo: UserEntity)  // 회원 등록 (코루틴 안에서 비동기적으로 수행)

    @Delete
    suspend fun deleteUser(userInfo: UserEntity)  // 회원 삭제 (코루틴 안에서 비동기적으로 수행)
}
  1. 추상 클래스 생성해 다음 Database 코드 작성
  • RoomDatabase 객체는 생성하는데 비용이 많이 들기 때문에 중복으로 생성하지 않도록 싱글톤으로 설정
  • @Volatile이란?
    • Java 변수를 Main Memory에 저장하겠다는 것을 명시하는 것
    • 매번 변수의 값을 Read, Write할 때마다 CPU Cache가 아닌 Main Memory에 저장하고 불러오기 때문에 변수 값 불일치 문제를 방지할 수 있음
  • 서로 다른 유저(스레드)가 동시에 데이터베이스에 접근하는 것을 막기 위해 syschronized 속성을 사용해 동기화
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase

@Database(
    entities = [UserEntity::class],  //  이 db에 어떤 테이블들이 있는지
    version = 1,  //  스키마가 바뀔 때 버전도 바뀌어야함
    exportSchema = false  //  스키마 구조를 폴더로 export할 수 있음
)
abstract class UserDatabase : RoomDatabase() {  // RoomDatabase 상속하는 추상클래스
    abstract fun getLoginDAO(): LoginDAO  // DAO를 반환하고 인수가 존재하지 않는 추상 함수

    companion object {
        @Volatile  // Java 변수를 Main Memory에 저장
        private var INSTANCE: UserDatabase? = null

        private fun buildDatabase(context: Context): UserDatabase = Room.databaseBuilder(
            context, UserDatabase::class.java, "db_user"
        ).build()

        fun getInstance(context: Context): UserDatabase = INSTANCE ?: synchronized(this) {
            INSTANCE ?: buildDatabase(context).also { INSTANCE = it }
        }
    }
}
profile
Android 짱이 되고싶은 개발 기록 (+ ios도 조금씩,,👩🏻‍💻)

0개의 댓글