일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- imageview
- kotlin
- fragment
- Jetpack Compose
- Navigation Component
- Safe Args
- Gradle
- electron
- Android
- Livedata
- room
- 주석
- Datastore
- ViewModel
- 일렉트론
- hilt
- 취업
- android studio
- 스플래시
- nav_graph
- 테마
- 안드로이드
- TypeConverter
- Binding Adapter
- 개발자
- asLiveData()
- themes.xml
- recyclerview
- 면접
- BottomNavigationView
- Today
- Total
나만 보는 일기장
[Room] Room의 구조와 사용법 본문
Room 지속성 라이브러리는 SQLite에 추상화 계층을 제공하여 SQLite를 완벽히 활용하면서 더 견고한 데이터베이스 액세스를 가능하게 합니다.
오늘은 Hilt와 ViewModel 등의 여러 라이브러리를 통해 Room을 사용하는 법을 알아보도록 하겠습니다.
Room의 구조
Room을 사용할 때 만들어 주어야 하는 것은 크게
1. DB에 들어가는 테이블의 구조인 Entity,
2. DB의 데이터에 접근할 수 있는 함수를 정의해 놓은 DAO,
3. DB 그 자체인 Database
3가지 입니다.
1. Entity
@Entity(tableName = Constants.TABLE_NAME)
class TeamBookmarkEntity(
var favoriteTeam: TeamData
) {
@PrimaryKey(autoGenerate = true)
var id: Int = 0
}
먼저 Entity는 @Entity 어노테이션으로 표시해 줍니다. 기본은 클래스 이름대로 테이블이 생성되지만, @Entity(tableName = 테이블 이름) 형식으로 테이블 이름을 따로 지정해 줄 수도 있습니다.
그다음 @PrimaryKey 어노테이션으로 기본키를 설정해 줍니다. 기본키는 직접 설정할 수도 있고, @PrimaryKey(autoGenerate = true)와 같이 자동으로 설정되도록 쓸 수도 있습니다.
2. DAO
@Dao
interface TeamBookmarkDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertTeamBookmark(teamBookmark: TeamBookmarkEntity)
@Query("SELECT * FROM team_bookmark_table ORDER BY id ASC;")
fun readTeamBookmark(): Flow<List<TeamBookmarkEntity>>
@Delete
suspend fun deleteTeamBookmark(teamBookmarkEntity: TeamBookmarkEntity)
}
DAO는 @Dao 어노테이션으로 표시해주고, 내부에 사용할 기능들을 만들어 줍니다.
단순 삽입, 삭제, 수정은 @Insert, @Delete, @Update 어노테이션을 사용하면 Room이 알아서 처리해주고,
세부적인 쿼리를 작성하기 위해서는 @Query 어노테이션을 달고 내부에 SQL문을 작성해 주면 됩니다.
3. Database
@Database(
entities = [TeamBookmarkEntity::class],
version = 1,
exportSchema = false
)
@TypeConverters(TeamBookmarkTypeConverter::class)
abstract class TeamBookmarkDatabase: RoomDatabase() {
abstract fun teamBookmarkDao(): TeamBookmarkDao
}
Database 역시 @Database 어노테이션으로 표시해 준 후, DB에서 사용할 엔티티들을 넣어줍니다. version은 테이블의 구조가 달라질 경우 올려주어야 한다고 하는데, 저는 자세히 모르겠습니다.
위에 나온 @TypeConverters 어노테이션의 경우, LocalDateTime 같은 Room에 그대로 집어넣을 수 없는 자료형의 경우에 String 같은 자료형으로 변환해주는 TypeConverter를 만들어 지정해준 것 입니다. TypeConverter는 @TypeConverter 어노테이션을 붙여 구현하면 됩니다.
@TypeConverter
fun localDateTimeToString(localDateTime: LocalDateTime): String =
localDateTime.format(DateTimeFormatter.ofPattern(localDateTimePattern))
@TypeConverter
fun stringToLocalDateTime(string: String): LocalDateTime =
LocalDateTime.parse(string, DateTimeFormatter.ofPattern(localDateTimePattern))
이제 Room의 구성요소는 만들었고, DI를 통해 DAO를 주입 받기 위해서 Module을 만들어줍니다.
@Module
@InstallIn(SingletonComponent::class)
object DatabaseModule {
@Provides
@Singleton
fun provideWakeUpTimeDataBase(@ApplicationContext context: Context): WakeUpTimeDatabase =
Room.databaseBuilder(context, WakeUpTimeDatabase::class.java, DATABASE_NAME).build()
@Provides
@Singleton
fun provideWakeUpTimeDao(database: WakeUpTimeDatabase) = database.wakeUpTimeDao()
}
위와 같이 만들어 주었습니다.
class Repository @Inject constructor(
private val wakeUpTimeDao: WakeUpTimeDao
) {
fun getWakeUpTimes(): Flow<List<WakeUpTimeEntity>> =
wakeUpTimeDao.getWakeUpTimes()
suspend fun insertWakeUpTime(wakeUpTimeEntity: WakeUpTimeEntity) =
wakeUpTimeDao.insertWakeUpTime(wakeUpTimeEntity)
suspend fun deleteWakeUpTime(wakeUpTimeEntity: WakeUpTimeEntity) =
wakeUpTimeDao.deleteWakeUpTime(wakeUpTimeEntity)
}
그 이후 Repository에 DAO를 주입해주었습니다. 데이터를 가져오는 함수는 Flow 형태로 가져오기 때문에 suspend 함수로 만들지 않았고 나머지는 suspend 함수로 만들었습니다.
@HiltViewModel
class MainViewModel @Inject constructor(
private val repository: Repository
) : ViewModel() {
fun getWakeUpTimes(): Flow<List<WakeUpTimeEntity>> = repository.getWakeUpTimes()
fun insertWakeUpTime(wakeUpTimeEntity: WakeUpTimeEntity) = viewModelScope.launch {
repository.insertWakeUpTime(wakeUpTimeEntity)
}
fun deleteWakeUpTime(wakeUpTimeEntity: WakeUpTimeEntity) = viewModelScope.launch {
repository.deleteWakeUpTime(wakeUpTimeEntity)
}
}
이후에 뷰모델에서 Repository를 가져와주고,
private fun checkIsTodaysWakeUpTimeSaved() = mainViewModel.getWakeUpTimes().asLiveData().observe(viewLifecycleOwner) { result ->
mainViewModel.isTodaysWakeUpTimeSaved = result.map { it.wakeUpTime.dayOfMonth }.contains(LocalDate.now().dayOfMonth)
applyLottieStyle()
}
그 이후 위와 같이 Flow를 LiveData로 변환해 값을 가져왔습니다.
'개발 > Android' 카테고리의 다른 글
[ImageView] 이미지 비율은 맞추면서, 크기는 꽉 채우고 싶어요!! (4) | 2022.04.09 |
---|---|
[DataStore] Preference DataStore 사용하기 (0) | 2022.04.07 |
[Android] View에 터치 효과 넣기 (0) | 2022.04.04 |
[RecyclerView] 스와이프, 드래그&드롭 효과를 가진 RecyclerView 만들기 (0) | 2022.03.26 |