๐Ÿ”ฅTIL๐Ÿ”ฅ์ŠคํŒŒ๋ฅดํƒ€ | Room

hyihyiยท2024๋…„ 1์›” 24์ผ
0

TIL

๋ชฉ๋ก ๋ณด๊ธฐ
39/70
post-thumbnail

๐Ÿ“– ์˜๊ตฌ์  ๋ฐ์ดํ„ฐ ์ €์žฅ ๋ฐฉ๋ฒ• 3๊ฐ€์ง€

1. SharedPreferences

2. DB

3. ํŒŒ์ผ ํ˜•ํƒœ

๐Ÿ“– Room

Room ๋ง๊ณ  SQL ์ข…๋ฅ˜ ์ค‘ ํ•˜๋‚˜์ธ SQLite๊ฐ€ ์žˆ์Œ
PC์šฉ ํ”„๋กœ๊ทธ๋žจ์ด ์•„๋‹ˆ๋ผ ์ข€ ๊ฐ€๋ณ์ง€๋งŒ SQLite๋ฅผ ์“ฐ๋ ค๋ฉด ๋ณต์žกํ•˜๋‹ค.
๊ทธ๋ž˜์„œ ๋‚˜์˜จ ๊ฒŒ Room์ด๋ผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

SQLite๋ฅผ ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” DB ๊ฐ์ฒด ๋งคํ•‘ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
Query๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ๋จ
Query ๊ฒฐ๊ณผ๋ฅผ LiveData๋กœ ํ•˜์—ฌ DB๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์‰ฝ๊ฒŒ UI๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Œ
์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ SQLite๋ณด๋‹ค Room์„ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅ

๐Ÿ“ Room ์ฃผ์š” 3์š”์†Œ

1. @Database

RoomDatabase๋ฅผ ์ƒ์†๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํด๋ž˜์Šค์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜

2. @Entity

Database ์•ˆ ํ…Œ์ด๋ธ”์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด ์Šคํ‚ค๋งˆ๋กœ ์ง€์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜

3. @Dao

ํด๋ž˜์Šค๋ฅผ DAO๋กœ ์ง€์ •ํ•˜๋Š” ์–ด๋…ธํ…Œ์ด์…˜
๊ธฐ๋ณธ์ ์ธ insert, delete, update SQL์€ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋ฉฐ ๋ณต์žกํ•œ SQL์€ ์ง์ ‘ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Œ

๐Ÿ“ Room ์‚ฌ์šฉํ•˜๊ธฐ

1. gradle ํŒŒ์ผ ์„ค์ •

plugins {
    ...
    
    id("kotlin-kapt")
}

dependencies{

	....
    implementation("androidx.room:room-runtime:2.6.1")
    annotationProcessor("androidx.room:room-compiler:2.6.1")
    kapt("androidx.room:room-compiler:2.6.1")
    // optional - Kotlin Extensions and Coroutines support for Room
    implementation("androidx.room:room-ktx:2.6.1")
    // optional - Test helpers
    testImplementation("androidx.room:room-testing:2.6.1")
    

2. Database

Entity๋“ค๊ณผ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋ฒ„์ „์„ @Database ์–ด๋…ธํ…Œ์ด์…˜์— ์ง€์ •ํ•จ
๊ธฐ์กด ๋ฒ„์ „์˜ Database์™€์˜ ๋™๊ธฐํ™”๋ฅผ ์œ„ํ•ด ๋ฒ„์ „์„ ๋งž์ถฐ์ฃผ๋Š” ๊ฒŒ ์ค‘์š”ํ•จ
๊ธฐ์กด์— ์ €์žฅ๋˜์–ด ์žˆ๋Š” Database๋ณด๋‹ค ๋ฒ„์ „์ด ๋†’์œผ๋ฉด Database๋ฅผ openํ•  ๋•Œ migration์„ ์ˆ˜ํ–‰ํ•˜๊ฒŒ ๋จ
Migration์„ ํ†ตํ•ด ํ…Œ์ด๋ธ”์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•จ
Migration ์ˆ˜ํ–‰ ๋ฐฉ๋ฒ•์€ RoomDatabase ๊ฐ์ฒด์˜ addmigration() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์•Œ๋ ค์คŒ

3. Entity ์ƒ์„ฑ

๋ชจ๋“  DB๋Š” ํ…Œ์ด๋ธ”์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ณ  ๊ทธ ํ…Œ์ด๋ธ”์ด ์–ด๋–ค ์ปฌ๋Ÿผ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”์ง€ ์ •์˜ํ•œ ๊ฒƒ์ด ์Šคํ‚ค๋งˆ
Entity๋Š” ํ…Œ์ด๋ธ” ์Šคํ‚ค๋งˆ ์ •์˜

4. DAO ์ƒ์„ฑ

DAO๋Š” interface๋‚˜ abstract class๋กœ ์ •์˜๋˜์–ด์•ผ ํ•จ
Annotation์— SQL ์ฟผ๋ฆฌ๋ฅผ ์ •์˜ํ•˜๊ณ  ๊ทธ ์ฟผ๋ฆฌ๋ฅผ ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์„ ์–ธ

๊ฐ€๋Šฅํ•œ annotation : @Insert, @Update, @Delete, @Query

@Insert, @Update, @Delete๋Š” SQL ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š์•„๋„ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•จ

โžกRoom์„ ์“ฐ๋Š” ์ด์œ  ์ค‘ ํ•˜๋‚˜

๋งŒ์•ฝ @Insert, @Update ์‹œ ๊ฐ’์ด ์ค‘๋ณต๋์„ ๋•Œ ์ฒ˜๋ฆฌํ•  ์˜ต์…˜์€ ์•„๋ž˜์™€ ๊ฐ™์Œ

  • OnConflictStrategy.ABORT: key ์ถฉ๋Œ์‹œ ์ข…๋ฃŒ
  • OnConflictStrategy.IGNORE: key ์ถฉ๋Œ ๋ฌด์‹œ
  • OnConflictStrategy.REPLACE: key ์ถฉ๋Œ์‹œ ์ƒˆ๋กœ์šด ๋ฐ์ดํ„ฐ๋กœ ๋ณ€๊ฒฝ
  • @Update๋‚˜ @Delete๋Š” primary key์— ํ•ด๋‹น๋˜๋Š” ํŠœํ”Œ์„ ์ฐพ์•„์„œ ๋ณ€๊ฒฝ/์‚ญ์ œ ํ•จ

@Query๋กœ ๋ฆฌํ„ด๋˜๋Š” ๋ฐ์ดํ„ฐ์˜ ํƒ€์ž…์„ LiveData<>๋กœ ํ•˜๋ฉด, ๋‚˜์ค‘์— ์ด ๋ฐ์ดํ„ฐ๊ฐ€ ์—…๋ฐ์ดํŠธ๋  ๋•Œ Observer๋ฅผ ํ†ตํ•ด ํ•  ์ˆ˜ ์žˆ์Œ

@Query์— SQL์„ ์ •์˜ํ•  ๋•Œ ๋ฉ”์†Œ๋“œ์˜ ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Œ

LiveData๋Š” ๋น„๋™๊ธฐ์ ์œผ๋กœ ๋™์ž‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— coroutine์œผ๋กœ ํ•  ํ•„์š”๊ฐ€ ์—†์Œ

5. Migration

์–ด๋Š ๋ฒ„์ „์—์„œ ์–ด๋Š ๋ฒ„์ „์œผ๋กœ ๋ฐ”๋€” ๋•Œ ์–ด๋–ค ๋™์ž‘์„ ํ•  ์ง€ ์ •ํ•ด์คŒ

6. UI์™€ ์—ฐ๊ฒฐ

RoomDatabase ๊ฐ์ฒด์—์„œ DAO ๊ฐ์ฒด๋ฅผ ๋ฐ›์•„์˜ค๊ณ  ์ด DAO ๊ฐ์ฒด์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ ‘๊ทผํ•จ
UI ์Šค๋ ˆ๋“œ์—์„œ ๋„คํŠธ์›Œํฌ๋‚˜ DB๋ฅผ ํ˜ธ์ถœํ•  ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— coroutine์„ ์“ฐ๊ณ runBlocking์„ ๊ฑธ์–ด๋†“์Œ

7. UI์™€ ์—ฐ๊ฒฐ-LiveData

LiveData<> ํƒ€์ž…์œผ๋กœ ๋ฆฌํ„ด๋˜๋Š” DAO ๋ฉ”์†Œ๋“œ ๊ฒฝ์šฐ
observe() ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ•ด Observer๋ฅผ ์ง€์ •ํ•˜๊ณ  ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ํ˜ธ์ถœ๋จ

๐Ÿ“ Room ์˜ˆ์ œ

1. Database ์ƒ์„ฑ

RoomDatabase ์ƒ์†๋ฐ›์Œ

2. DAO ์ƒ์„ฑ

์ฟผ๋ฆฌ ๋‚ ๋ฆด ๋•Œ ์‚ฌ์šฉ

3. MyEntity ์ƒ์„ฑ

Student ํด๋ž˜์Šค๊ฐ€ ๋“ค์–ด์žˆ์Œ
student_id๋ž€ ์ปฌ๋Ÿผ๋ช…์œผ๋กœ

4. MainActivity

binding.queryStudent.setOnClickListener {
    val name = binding.editStudentName.text.toString()
    CoroutineScope(Dispatchers.IO).launch {

        val results = myDao.getStudentByName(name)

        if (results.isNotEmpty()) {
            val str = StringBuilder().apply {
                results.forEach { student ->
                    append(student.id)
                    append("-")
                    append(student.name)
                }
            }
            withContext(Dispatchers.Main) {
                binding.textQueryStudent.text = str
            }
        } else {
            withContext(Dispatchers.Main) {
                binding.textQueryStudent.text = ""
            }
        }
    }
}

withContext(Dispatchers.Main)์œผ๋กœ ์Œ“์—ฌ์žˆ๋Š” ์ด์œ 
โžกDB์˜ ๊ฒฐ๊ณผ์— ๋”ฐ๋ผ์„œ ๋„๋Š” ๋ฃจํ‹ด ์ž์ฒด๊ฐ€ Main UiThread๊ฐ€ ์•„๋‹Œ ๋ณ„๋„์˜ Thread์—์„œ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— UI ์—…๋ฐ์ดํŠธ๋ฅผ MainThread์—์„œ ํ•˜๊ธฐ ์œ„ํ•ด์„œ withContext ์‚ฌ์šฉ

๐Ÿ“Œ์ •๋ฆฌ

RoomData๋ฅผ ์“ฐ๋ ค๋ฉด

Database ํด๋ž˜์Šค ๋งŒ๋“ค๊ณ 
์ฟผ๋ฆฌํ•˜๋Š” Dao,
ํ…Œ์ด๋ธ” ๋“ค์–ด๊ฐ€๋Š” Entity ๋งŒ๋“ค์–ด์„œ

MainActivity์—์„œ Database ์ธ์Šคํ„ด์Šค ์ƒ์„ฑํ•˜๊ณ 
Dao ํ†ตํ•ด์„œ ์ฟผ๋ฆฌํ•˜๊ณ 
๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๋Š”๋‹ค

profile
๋‚ด๊ฐ€ ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๊ฒŒ ์“ฐ๋Š” ๋ธ”๋กœ๊ทธ

0๊ฐœ์˜ ๋Œ“๊ธ€