본문 바로가기
Android

Android Room DB 간단한 메모DB 만들어보기 + 주의할점

by kkong93 2024. 1. 5.
반응형

1. 의존성 추가 (최신 버전으로 업데이트)

dependencies {
    def room_version = "2.4.1"

    implementation "androidx.room:room-runtime:$room_version"
    kapt "androidx.room:room-compiler:$room_version"

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

 

2.entity추가

import androidx.room.Entity
import androidx.room.PrimaryKey

@Entity
data class Memo(
    @PrimaryKey(autoGenerate = true) val id: Int,
    val title: String,
    val content: String
)

 

3.Dao class 만들기

import androidx.room.*
import kotlinx.coroutines.flow.Flow

@Dao
interface MemoDao {
    @Query("SELECT * FROM memo")
    fun getAll(): Flow<List<Memo>>

    @Insert
    suspend fun insert(memo: Memo)

    @Update
    suspend fun update(memo: Memo)

    @Delete
    suspend fun delete(memo: Memo)
}

 

DB만들기

import androidx.room.Database
import androidx.room.RoomDatabase

@Database(entities = [Memo::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun memoDao(): MemoDao
}

 

Repository 사용해 Dao 감싸주기

class MemoRepository(private val memoDao: MemoDao) {
    val memos: Flow<List<Memo>> = memoDao.getAll()

    suspend fun insert(memo: Memo) {
        memoDao.insert(memo)
    }

    suspend fun update(memo: Memo) {
        memoDao.update(memo)
    }

    suspend fun delete(memo: Memo) {
        memoDao.delete(memo)
    }
}

✔ Repositoy 패턴을 사용하는 이유

 

- 추상화와 분리의 원칙: Repository는 데이터 소스와 나머지 애플리케이션 사이의 중간 계층으로 작동합니다. 이렇게 하면 데이터베이스 로직이 UI 또는 비즈니스 로직과 분리되어 앱의 구조가 더 깨끗하고 관리하기 쉬워집니다.
- 데이터 소스 관리: 여러 데이터 소스(로컬 Room DB, 원격 서버, 캐시 등)가 있을 수 있으며, Repository는 이러한 다양한 데이터 소스를 통합하여 일관된 방식으로 데이터를 제공합니다.
- 테스트 용이성: Repository 패턴을 사용하면 의존성 주입을 통해 테스트 중에 다른 구현으로 교체하기 쉽습니다. 이렇게 하면 데이터베이스 연산을 모방하는 가짜(fakes) 또는 목(mock) 객체를 사용하여 단위 테스트가 용이해집니다.
- 코드 재사용 및 유지보수: 공통 데이터 액세스 패턴과 함수를 Repository에 정의함으로써 애플리케이션 전반에 걸쳐 코드의 재사용성과 유지보수성이 향상됩니다.
- 비동기 처리: Room DB의 작업은 기본적으로 비동기적으로 수행되어야 합니다. Repository를 통해 이러한 비동기 처리를 더 효과적으로 관리할 수 있습니다. 예를 들어, Kotlin의 코루틴과 같은 비동기 프로그래밍 기법을 Repository에서 통합하여 사용할 수 있습니다.
- 애플리케이션의 확장성: 나중에 데이터 소스를 변경하거나 추가해야 할 경우, Repository 패턴을 사용하면 이러한 변경이나 확장이 애플리케이션의 나머지 부분에 미치는 영향을 최소화할 수 있습니다.

 

viewmodel 에서 사용하기

import androidx.lifecycle.ViewModel
import androidx.lifecycle.asLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch

class MemoViewModel(private val repository: MemoRepository) : ViewModel() {
    val memos = repository.memos.asLiveData()

    fun insert(memo: Memo) = viewModelScope.launch {
        repository.insert(memo)
    }

    fun update(memo: Memo) = viewModelScope.launch {
        repository.update(memo)
    }

    fun delete(memo: Memo) = viewModelScope.launch {
        repository.delete(memo)
    }
}

 

❌RoomDatabase를 사용할 때 주의할 점

 

메인 스레드에서의 데이터베이스 작업 피하기: Room은 기본적으로 메인 스레드에서의 긴 작업(예: 쿼리 수행)을 허용하지 않습니다. 이는 UI가 멈추는 것을 방지하기 위함입니다. 따라서 모든 데이터베이스 작업은 백그라운드 스레드에서 수행되어야 합니다. Kotlin 코루틴을 사용하는 것이 좋은 방법 중 하나입니다.

데이터베이스 인스턴스 관리: 데이터베이스 인스턴스를 생성하고 관리하는 과정은 자원을 많이 사용할 수 있습니다. 따라서 싱글톤 패턴을 사용하여 전역적으로 하나의 인스턴스만 생성되도록 관리하는 것이 좋습니다.

LiveData 또는 Flow 사용: Room과 함께 LiveData 또는 Kotlin Flow를 사용하여 데이터 변경사항을 관찰하고 UI를 자동으로 업데이트 할 수 있습니다. 이렇게 하면 데이터베이스의 데이터가 변경될 때 UI가 자동으로 반응하여 최신 상태를 반영할 수 있습니다.

TypeConverter 사용: Room은 기본적으로 일부 복잡한 데이터 타입(예: Date, custom objects 등)을 지원하지 않습니다. 이러한 타입을 저장하려면 TypeConverter를 작성하여 복잡한 타입을 Room이 지원하는 기본 타입으로 변환해야 합니다.

스키마 마이그레이션 관리: 애플리케이션 업데이트 중에 데이터베이스 스키마가 변경되는 경우, 적절한 마이그레이션 로직을 구현해야 합니다. 이를 통해 기존 데이터의 손실을 방지하고 데이터 무결성을 유지할 수 있습니다.

SQL 쿼리 주의 깊게 작성: Room은 SQL 쿼리 오류를 컴파일 시간에 발견할 수 있도록 도와주지만, 여전히 SQL 쿼리를 주의 깊게 작성해야 합니다. 특히 JOIN, WHERE 절 등 복잡한 쿼리는 성능에 영향을 줄 수 있으므로 최적화가 필요합니다.

반응형

댓글