๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
Dev/Android

[Android] Room์„ ์ด์šฉํ•˜์—ฌ ๋กœ์ปฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ €์žฅํ•˜๊ธฐ

by JUNE.C 2021. 6. 10.

๐Ÿง Room?

 ๋กœ์ปฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ์—์„œ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ธ SQLite๊ฐ€ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ ๊ตฌ๊ธ€์—์„œ 2017๋…„ AAC(Android Architecture Components)๋ฅผ ๋‚ด๋†“์Œ์œผ๋กœ SQLite๋ฅผ ์ง์ ‘ ์‚ฌ์šฉํ•˜์—ฌ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค Room์„ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ–ˆ๋‹ค. ๊ถŒ์žฅ ์‚ฌ์œ ๋Š” ์•„๋ž˜ ์•ˆ๋“œ๋กœ์ด๋“œ SQLite ๊ณต์‹ ๋ฌธ์„œ Caution ๋‚ด์šฉ์„ ์ฐธ๊ณ ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค.

SQLite ์‚ฌ์šฉ ์ „ caution (์ถœ์ฒ˜: developer.android.com)

  1. SQL Query๋ฅผ ์ง์ ‘ ์ž‘์„ฑํ–ˆ์–ด์•ผ ํ–ˆ๊ณ , ์ด๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์ด ๋ถˆ๊ฐ€ํ•˜๋‹ค๋Š” ์ 
  2. Database Scheme์ด ๋ณ€๊ฒฝ๋  ๋•Œ ์ผ์ผ์ด Query๋ฅผ ์—…๋ฐ์ดํŠธํ•ด์•ผํ•œ๋‹ค๋Š” ์ 
  3. ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ ๋งŽ์€ boilerplate code๋ฅผ ์ž‘์„ฑํ•ด์•ผํ•œ๋‹ค๋Š” ์ 

 

 Room์€ SQLite์˜ ์ถ”์ƒ ๋ ˆ์ด์–ด๋ฅผ ์ œ๊ณตํ•˜์—ฌ ๋ชจ๋“  SQLite์˜ ๊ธฐ๋Šฅ๋“ค์„ ์ด์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉด์„œ ๋” ํŽธํ•˜๊ฒŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค.

 ๋‹น์—ฐํ•˜๊ฒŒ ์œ„์—์„œ ๋งํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ๊ฐ์ฒด๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์œผ๋ฉฐ, ์ง์ ‘ Query๋ฅผ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ ๋„ ๊ธฐ๋ณธ์ ์ธ CRUD ์ž‘์—…์„ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 ๋˜ํ•œ RxJava, LiveData, Flow์™€ ๊ฐ™์€ Observable ๊ฐ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•˜๋ฉฐ ํ…Œ์ŠคํŒ… ๋˜ํ•œ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ง€์›ํ•ด์ค€๋‹ค.

 


๐Ÿ‘จ‍๐Ÿ‘ฉ‍๐Ÿ‘ง‍๐Ÿ‘ฆ Room Component

 ๐Ÿ“Œ Entity

 Entity๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•  ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์ •์˜ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ฆ‰, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ํ…Œ์ด๋ธ” Column ์ •๋ณด์ด๋‹ค. ์—ฌ๊ธฐ์„œ ์ •์˜๋œ ๋ฐ์ดํ„ฐ๋“ค์ด ๋ชจ์—ฌ ํ…Œ์ด๋ธ”์„ ๊ตฌ์„ฑํ•˜๊ฒŒ ๋œ๋‹ค.

 

 @Entity ์–ด๋…ธํ…Œ์ด์…˜์ด ์„ค์ •๋œ Data class๋กœ ์ •์˜ํ•˜๋ฉด ๋œ๋‹ค.

@Entity(tableName = "CONTENT")
data class Todo(
    @PrimaryKey(autoGenerate = true) @ColumnInfo(name = "t_id") val tId: Int = 0,
    @ColumnInfo(name = "content") val content: String,
    @ColumnInfo(name = "is_checked") var isChecked: Boolean = false,
    @ColumnInfo(name = "created_at") val createdAt: Long = System.currentTimeMills()
)

 @Entity ์–ด๋…ธํ…Œ์ด์…˜ Parameter์— ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด ์—ฌ๋Ÿฌ ์„ค์ •์„ ์ค„ ์ˆ˜ ์žˆ๋‹ค. ํ•ด๋‹น ๋‚ด์šฉ์€ ๊ณต์‹ ๋ฌธ์„œ(@Entity)๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

์œ„ ์ฝ”๋“œ์—์„œ๋Š” tableName์„ ์ •์˜ํ–ˆ์œผ๋‚˜ SQLite์—์„œ๋Š” ํ…Œ์ด๋ธ” ์ด๋ฆ„์„ ๋Œ€์†Œ๋ฌธ์ž ๊ตฌ๋ณ„ํ•˜์ง€ ์•Š์œผ๋ฉฐ, default ๊ฐ’์€ ๋ฐ์ดํ„ฐ ํด๋ž˜์Šค ์ด๋ฆ„์ด ๋˜๋ฏ€๋กœ ํด๋ž˜์Šค ์ด๋ฆ„๊ณผ ๋™์ผํ•˜๋‹ค๋ฉด ์ž‘์„ฑํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

 

 Room Entity๋Š” ๋ฐ˜๋“œ์‹œ 1๊ฐœ ์ด์ƒ์˜ PrimaryKey๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ํ•ด๋‹น Field์— @PrimaryKey ์–ด๋…ธํ…Œ์ด์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

PrimaryKey์˜ ์†์„ฑ์—๋Š” autoGenerate๊ฐ€ ์žˆ๋‹ค. true๋กœ ํ•  ๊ฒฝ์šฐ ์œ ๋‹ˆํฌํ•œ ๊ฐ’์„ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.

@Entity์˜ ์†์„ฑ์— Primary Keys๋ฅผ ์–ด๋ ˆ์ด ํ˜•ํƒœ๋กœ๋„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Œ์œผ๋กœ ํ•„์š”์‹œ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

 

 @ColumInfo ์–ด๋…ธํ…Œ์ด์…˜์€ Field ๊ฐ’์˜ ์†์„ฑ์„ ๋ช…์‹œํ•  ์ˆ˜ ์žˆ๋‹ค.

Kotlin์˜ ๋„ค์ด๋ฐ ์ปจ๋ฒค์…˜์€ camelCase์ด์ง€๋งŒ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์—์„  ๋ณดํ†ต snake_case๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ์— ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•ด์คฌ๋‹ค.

Default๋Š” field ์ด๋ฆ„์ด ๋œ๋‹ค. ์ด์™ธ์˜ ์†์„ฑ์€ ๊ณต์‹ ๋ฌธ์„œ(@ColumInfo)๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

 

 

 ๐Ÿ“Œ DAO(Data Access Object)

 Room์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ง์ ‘ ์ ‘๊ทผํ•˜์ง€ ์•Š๊ณ  DAO๋ผ๋Š” ๊ฐ์ฒด๋ฅผ ์ •์˜ํ•˜์—ฌ ์ ‘๊ทผํ•ด์•ผํ•œ๋‹ค.

 DAO๋Š” ๋ฌด์กฐ๊ฑด Interface ๋˜๋Š” Abstract class๋กœ ์ •์˜๋˜์–ด์•ผ ํ•œ๋‹ค. ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ DAO ์–ด๋…ธํ…Œ์ด์…˜์„ ์ฐพ์•„ ๊ตฌํ˜„ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

๋˜ํ•œ, ์ด๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ ์˜ค๋ฅ˜๋ฅผ ์ปดํŒŒ์ผ ์‹œ์ ์—์„œ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 Entity์— ๋Œ€ํ•ด ์ž๋™์™„์„ฑ์„ ์ง€์›ํ•˜๊ธฐ์— Query ์ž‘์„ฑ์‹œ์— ์˜คํƒ€๋ฅผ ์ค„์—ฌ์ฃผ๊ธฐ๋„ ํ•œ๋‹ค.

 

@Dao
interface TodoDao {
    @Insert
    fun insertTodoContent(vararg todo: Todo)

    @Delete
    fun deleteTodoContent(todo: Todo)

    @Update
    fun updateTodoCheckState(todo: Todo)
    
    @Query("SELECT * FROM CONTENT ORDER BY created_at DESC")
    fun getTodoContents(): List<Todo>
}

 @Dao ์–ด๋…ธํ…Œ์ด์…˜์„ ์ด์šฉํ•˜์—ฌ Room์—๊ฒŒ DAO class์ž„์„ ์•Œ๋ ค์ค€๋‹ค.

 

 @Insert ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ฉ”์†Œ๋“œ์— ์ง€์ •ํ•  ๊ฒฝ์šฐ ๋ชจ๋“  ๋งค๊ฐœ๋ณ€์ˆ˜๋ฅผ ์‚ฝ์ž…ํ•˜๋Š” ๊ตฌํ˜„์„ ์ž๋™์œผ๋กœ ๋งŒ๋“ค์–ด์ค€๋‹ค.

์—ฌ๋Ÿฌ ๋งค๊ฐœ๋ณ€์ˆ˜ ํƒ€์ž…์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค๋Š” ํŠน์„ฑ์œผ๋กœ ๋‹จ์ผ ๊ฐ์ฒด ๋˜๋Š” ๋ฐฐ์—ด ํ˜•ํƒœ ๋“ฑ ๋ชจ๋“  ๋ฐ์ดํ„ฐ ์ž…๋ ฅ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

์œ„ ์ฝ”๋“œ์—์„œ๋Š” vararg ๊ฐ€๋ณ€ ์ธ์ž๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ๊ฐ์ฒด๋ฅผ ๋ฐ›๋„๋ก ํ•˜์˜€๋‹ค.

 Insert ์†์„ฑ์œผ๋กœ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•  ๊ฒƒ์ธ์ง€์— ๋Œ€ํ•œ ์˜ต์…˜์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

Option Description
ABORT (default) ํŠธ๋žœ์žญ์…˜์„ ๋กค๋ฐฑํ•œ๋‹ค.
REPLACE ๊ธฐ์กด rows๋ฅผ ์ƒˆ๋กœ์šด rows๋กœ ๋Œ€์ฒดํ•œ๋‹ค.
IGNORE ๊ธฐ์กด rows๋ฅผ ์ง€ํ‚จ๋‹ค.(๋ฌด์‹œํ•œ๋‹ค)
@Insert(OnConflict = OnConflictStrategy.IGNORE)
fun insertTodoContent(vararg todo: Todo)

 ์œ„์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋” ์ž์„ธํ•œ ๋‚ด์šฉ์€ ๊ณต์‹ ๋ฌธ์„œ(@Insert)๋ฅผ ์ฐธ๊ณ ํ•˜์ž.

 

 @Delete ์–ด๋…ธํ…Œ์ด์…˜์€ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. PrimaryKey์— ๋งค์นญ๋˜๋Š” Entity๋ฅผ ์ฐพ์•„ ๊ฐ’์„ ์‚ญ์ œํ•œ๋‹ค.

 

 @Update ์–ด๋…ธํ…Œ์ด์…˜์€ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐฑ์‹ ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. Delete์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ PrimaryKey์— ๋งค์นญ๋˜๋Š” ๊ฐ’์„ ์ฐพ๋Š”๋‹ค.

 

 @Query ์–ด๋…ธํ…Œ์ด์…˜์€ ์ง์ ‘ Query๋ฅผ ์ž‘์„ฑํ•˜์—ฌ SQL์„ ์ž‘๋™์‹œํ‚ฌ ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ ๋•Œ ์ฃผ๋กœ ์‚ฌ์šฉ๋˜๋ฉฐ R/W ์ž‘์—…์„ ๋ชจ๋‘ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

 Parameter๋ฅผ ์ด์šฉํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด Query๋ฅผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค. parameter๊ฐ€ LIKE์ ˆ ๋’ค์— ์ฝœ๋ก ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

@Query("SELECT * FROM CONTENT WHERE content LIKE :content ORDER BY created_at DESC")
fun getTodoMatchingContents(content: String): List<Todo>

 

 * Flow, LiveData, Rxjava2 ๋“ฑ์˜ Observable ๊ฐ์ฒด๋กœ๋„ ๋ฐ˜ํ™˜์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, PagingSource(Paging 3) ๊ฐ์ฒด๋„ ์ตœ๊ทผ ์ง€์›ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋‹ค.

 

 

 ๐Ÿ“Œ Database

  Database๋Š” ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์—ฐ๊ฒฐ์„ ์œ„ํ•œ ์•ก์„ธ์Šค ํฌ์ธํŠธ ์—ญํ• ์„ ํ•œ๋‹ค.

@Database(entities = [Todo::class], version = 1)
abstract class AppDatabase: RoomDatabase() {

    abstract fun getTodoDao(): TodoDao

    companion object {
        @Volatile private var instance: AppDatabase? = null

        fun getInstance(context: Context): AppDatabase {
            return instance ?: synchronized(this) {
                instance ?: buildDatabase(context).also { instance = it }
            }
        }

        private fun buildDatabase(context: Context): AppDatabase {
            return Room.databaseBuilder(context, AppDatabase::class.java, "todo.db")
            	//.allowMainThreadQueries()
                .build()
        }
    }
}

 Database ํด๋ž˜์Šค๋Š” RoomDatabase๋ฅผ ์ƒ์†๋ฐ›๋Š” Abstract class์ด์–ด์•ผ ํ•œ๋‹ค.

ํด๋ž˜์Šค์—๋Š” @Database ์–ด๋…ธํ…Œ์ด์…˜์ด ํฌํ•จ๋˜์–ด์•ผ ํ•˜๋ฉฐ ์†์„ฑ์—๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์‚ฌ์šฉ๋  Entity๋“ค์„ ์–ด๋ ˆ์ด ํ˜•์‹์œผ๋กœ ๋‹ด๋Š”๋‹ค.

๋˜ํ•œ Database version์„ ๊ด€๋ฆฌํ•œ๋‹ค. ๋ฐ์ดํ„ฐ Scheme์ด ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ Migration๊ณผ ๊ฐ™์€ ์ž‘์—…์„ ์ˆ˜์›”ํžˆ ์ˆ˜ํ–‰ํ•œ๋‹ค.

 

 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐ์ฒด๋ฅผ singleton์œผ๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ๋ฐ”๋žŒ์งํ•˜๋‹ค. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜๊ฒŒ ๋˜๋ฉด ์ด ์ž์ฒด์—๋„ ๋งŽ์€ ๋น„์šฉ์ด ๋“ค์–ด๊ฐ€๋ฉฐ, ๊ตฌ๊ธ€ ๋ฌธ์„œ์— ๋”ฐ๋ฅด๋ฉด ๋‹จ์ผ ํ”„๋กœ์„ธ์Šค ๋‚ด์—์„œ ์—ฌ๋Ÿฌ ์ธ์Šคํ„ด์Šค์— ์•ก์„ธ์Šคํ•  ํ•„์š”๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค๊ณ  ํ•œ๋‹ค.

๋˜ํ•œ ์„œ๋กœ ๋‹ค๋ฅธ ์Šค๋ ˆ๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ํ•œ ๋ฒˆ์— ์ ‘๊ทผํ•˜๋ ค๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ ์œ„ํ•ด synchronized๋ฅผ ํ†ตํ•˜์—ฌ ๋™๊ธฐํ™”๋ฅผ ์‹œ์ผœ์ค„ ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

 

 Room.databaseBuilder() ๋˜๋Š” Room.inMemoryDatabaseBuilder()๋กœ ์ธ์Šคํ„ด์Šค๋ฅผ ์–ป์„ ์ˆ˜ ์žˆ๋‹ค. ํ›„์ž๋Š” ํ”„๋กœ์„ธ์Šค ์ข…๋ฃŒ ์‹œ์— ์‚ฌ๋ผ์ง€๋Š” ๋ฉ”๋ชจ๋ฆฌ ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์ด๋‹ค.

 

 ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ž‘์—…์€ UI performance๊ฐ€ ์ €ํ•˜๋˜๋Š” ๊ฒƒ์„ ๋ง‰๊ธฐ์œ„ํ•ด Main Thread์—์„œ์˜ ์ž‘๋™์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค.

Coroutine, RxJava, Thread ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ์žˆ๊ฒ ๋‹ค.

Room ์ฟผ๋ฆฌ๋ฅผ Flow<T>๋กœ ๋ฐ˜ํ™˜ํ•˜๊ฒŒ ๋  ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ Background Thread์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ ์ด๋ฅผ ์•Œ์•„๋ด๋„ ์ข‹๋‹ค.

 allowMainThreadQueries() ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด์„œ Main Thread ์ž‘๋™์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ์œผ๋‚˜ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

์ฃผ์„์œผ๋กœ ๋‚จ๊ฒจ๋‘” ์ด์œ ๋Š” ์œ„ ๋ฐฉ๋ฒ•๋“ค์„ ํฌ์ŠคํŒ…์—์„œ ์„ค๋ช…ํ•ด์ค„ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋ฅด๋Š”๋ฐ ๋นจ๋ฆฌ ์‚ฌ์šฉํ•ด์•ผํ•  ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ๋‚จ๊ฒจ๋‘”๋‹ค.

๋‹ค์‹œ ํ•œ๋ฒˆ ๋งํ•˜์ง€๋งŒ Main Thread์—์„œ์˜ ์ž‘๋™์„ ๊ถŒ์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค.

AppDatabase().getInstace(context).getTodoDao().getTodoContents() ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•˜๋ฉด๋œ๋‹ค ๊นŒ์ง€ ์•Œ๋ ค์ค˜์•ผ ํ•  ๊ฒƒ ๊ฐ™๋‹ค.

 


๐Ÿ”— Dependency

ํฌ์ŠคํŒ… ์ž‘์„ฑ ๋‹น์‹œ ์ตœ์‹  Stable ๋ฒ„์ „์€ 2.3.0์ด๋‹ค. Release ํŽ˜์ด์ง€์—์„œ ์ตœ์‹  ๋ฒ„์ „์„ ํ™•์ธํ•˜์ž.

plugins {
	id 'kotlin-kapt'
}

dependencies {
    def room_version = "2.3.0"

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

 


๐Ÿ“• Reference & ํ•จ๊ป˜ํ•˜๋ฉด ์ข‹์€ ๊ธ€

- Reference

์•ˆ๋“œ๋กœ์ด๋“œ ๊ณต์‹ ๋ฌธ์„œ - Room

Android Codelabs - Room with a View

 

- ํ•จ๊ป˜ํ•˜๋ฉด ์ข‹์€ ๊ธ€

7 Pro-tips for Room in medium

No more LiveData in Your Repository: There are better options

Java Volatile ์˜๋ฏธ

 


 AAC๋ฅผ ํฌํ•จํ•œ Jetpack ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋Œ€ํ•˜์—ฌ ์ง€์†์ ์œผ๋กœ ํฌ์ŠคํŒ…ํ•  ์˜ˆ์ •์ด๋‹ค.

 Github Repository๋ฅผ ํ†ตํ•˜์—ฌ ์ƒ˜ํ”Œ ํ”„๋กœ์ ํŠธ๋ฅผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ณ„๋กœ ๊ด€๋ฆฌ(branch)ํ•  ๊ฒƒ์ด๋ฏ€๋กœ ๊ด€์‹ฌ์ด ์žˆ์œผ๋ฉด ๋“ค๋ ค๋„ ์ข‹๋‹ค. ๊นƒํ—ˆ๋ธŒ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๋Œ“๊ธ€