💜 Room의 이점
- SQL 쿼리의 컴파일 시간 확인
- 반복적이고 오류가 발생하기 쉬운 상용구 코드를 최소화하는 편의 주석
- 간소화된 데이터베이스 이전 경로
build.gradle (:app)
plugins {
id 'kotlin-kapt'
}
dependencies {
// ROOM Database 사용
implementation("androidx.room:room-runtime:2.4.3")
annotationProcessor("androidx.room:room-compiler:2.4.3")
kapt("androidx.room:room-compiler:2.4.3")
implementation("androidx.room:room-ktx:2.4.3")
}
@Entity(tableName = "table_bookmark")
data class ParkBookmarkEntity(
@PrimaryKey
val parkingCode: String = "",
val parkingName: String = "",
val addr: String = "",
val lat: Double = 0.0,
val lng: Double = 0.0,
val tel: String = "",
val operation_rule_nm: String = "",
var isSelected:Boolean = false
)
@Dao
interface ParkDAO {
@Query("SELECT * FROM table_bookmark")
fun getAll(): List<ParkBookmarkEntity>
// parkingCode 에 해당하는 selected 값 가져오기
@Query("SELECT isSelected FROM table_bookmark WHERE parkingCode = :parkingCode")
fun getBookmark(parkingCode: String) : Boolean
// bookmark 저장 - 중복 값 충돌 발생 시 새로 들어온 데이터로 교체.
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun saveBookmark(bookmarkEntity: ParkBookmarkEntity)
// bookmark 삭제
@Delete
fun deleteBookmark(bookmarkEntity: ParkBookmarkEntity)
}
@Database(entities = [ParkBookmarkEntity::class], version = 1)
abstract class ParkDatabase : RoomDatabase() {
abstract fun parkDao(): ParkDAO
// 데이터 베이스 객체를 싱글톤으로 인스턴스.
companion object {
private var instance: ParkDatabase? = null
@Synchronized
fun getInstance(context: Context): ParkDatabase? {
if (instance == null)
synchronized(ParkDatabase::class) {
instance = Room.databaseBuilder(
context.applicationContext,
ParkDatabase::class.java,
"park.db"
)
.build()
}
return instance
}
fun destroyInstance() {
instance = null
}
}
}
class ParkBottomSheetFragment(val mContext : Context) : BottomSheetDialogFragment() {
private var db: ParkDatabase? = null
override fun onCreateView(...): View? {
super.onCreateView(inflater, container, savedInstanceState)
// 생략
db = ParkDatabase.getInstance(mContext)
}
// 버튼 xml
<androidx.appcompat.widget.AppCompatButton
android:id="@+id/btn_bookmark"
android:layout_width="wrap_content"
android:layout_height="36dp"
android:background="@drawable/selector_btn_bookmark"
android:drawableLeft="@drawable/ic_heart"
android:paddingHorizontal="@dimen/margin_20"
android:layout_marginEnd="10dp"
android:text="즐겨찾기"
android:textColor="@color/white"
android:textSize="16dp"
android:textStyle="bold" />
// selector
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="false">
<shape android:shape="rectangle">
<solid android:color="@color/main_color" />
</shape>
</item>
<item android:state_selected="true">
<shape android:shape="rectangle">
<solid android:color="@color/main_purple1" />
</shape>
</item>
</selector>
// 즐겨찾기 저장하기
btnBookmark.setOnClickListener {
// UI 와 상호작용하기 위해 사용.
CoroutineScope(Dispatchers.Main).launch {
val temp: Deferred<Boolean> = async(Dispatchers.IO) { // async 로 결과를 반환
val isBookmarked = db!!.parkDao().getBookmark(data.PARKING_CODE)
if (isBookmarked) { // 이미 즐겨찾기 되어있으면 삭제
db!!.parkDao().deleteBookmark(bookmarkData)
false
} else { // 없으면 즐겨찾기 저장
db!!.parkDao().saveBookmark(bookmarkData)
true
}
}
// UI 변경
val selected = temp.await() // async 작업이 완료 되고 난 후 호출.
it.isSelected = selected
}
}
// 즐겨찾기 된 데이터 가져오기
btnGetData.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch { // 코루틴 사용 비동기로 실행.
val parkData = db!!.parkDao().getAll()
Utils.Log("db 조회 -> $parkData")
}
}
// 즐겨찾기 삭제하기
btnDeleteData.setOnClickListener {
CoroutineScope(Dispatchers.IO).launch { // 코루틴 사용 비동기로 실행.
db!!.parkDao().deleteBookmark(bookmarkData)
Utils.Log("즐겨찾기 삭제 완료")
}
}
순서대로 클릭해서 즐겨찾기를 하고, 리스트를 가져오고, 삭제한 후, 잘 찍히는 로그들을 확인할 수 있다.
공식 문서 : https://developer.android.com/training/data-storage/room?hl=ko