๐Ÿ“ฑViewModel๊ณผ Room์œผ๋กœ ๋ฐฐ์šฐ๋Š” ์•ˆ๋“œ๋กœ์ด๋“œ

HBยท2025๋…„ 5์›” 20์ผ

๐Ÿ’ ์•ˆ๋“œ๋กœ์ด๋“œ Jetpack & ViewModel

์•ˆ๋“œ๋กœ์ด๋“œ Jetpack

  • Jetpack์€ ์•ˆ๋“œ๋กœ์ด๋“œ ์•ฑ ๊ฐœ๋ฐœ์„ ๋” ์‰ฝ๊ณ , ๋น ๋ฅด๊ณ , ์•ˆ์ •์ ์œผ๋กœ ๋งŒ๋“ค์–ด์ฃผ๋Š” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ชจ์Œ
  • ๋Œ€ํ‘œ ๊ตฌ์„ฑ ์š”์†Œ
    • LiveData : ์ƒ๋ช… ์ฃผ๊ธฐ ์ธ์‹ ๋ฐ์ดํ„ฐ ํ™€๋”
    • ViewModel : UI ์ƒํƒœ ๊ด€๋ฆฌ
    • Room : SQLite๋ฅผ ์ถ”์ƒํ™”ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
    • Compose : ์„ ์–ธํ˜• UI ๊ฐœ๋ฐœ ํˆดํ‚ท

๊ตฌ์‹ ์•„ํ‚คํ…์ฒ˜์˜ ๋ฌธ์ œ

  • ๊ธฐ์กด์—๋Š” Activity์— UI์™€ ๋กœ์ง์„ ๋ชจ๋‘ ๋ชฐ์•„๋„ฃ๋Š” ๋ฐฉ์‹

  • ํ™”๋ฉด ํšŒ์ „ ์‹œ ๋ฐ์ดํ„ฐ ์†์‹ค

  • ์ฝ”๋“œ์˜ ๋†’์€ ๊ฒฐํ•ฉ๋„ โ†’ ์œ ์ง€๋ณด์ˆ˜ ์–ด๋ ค์›€

  • ํ…Œ์ŠคํŠธ ์–ด๋ ค์›€

Jetpack ๊ธฐ๋ฐ˜ ๋ชจ๋˜ ์•„ํ‚คํ…์ฒ˜

UI (Compose)
โ†“
ViewModel (UI ์ƒํƒœ/๋กœ์ง)
โ†“
Repository (๋ฐ์ดํ„ฐ ์ค‘๊ฐœ)
โ†“
Room, Network (DB/API)

ViewModel ๊ตฌํ˜„

  • mutableStateOf๋Š” Compose์—์„œ UI ์ƒํƒœ๋ฅผ ์ž๋™๊ฐ์ง€
class DemoViewModel : ViewModel() {
    var temperature by mutableStateOf("")
}

์ƒํƒœ ๊ธฐ๋ฐ˜ ViewModel

  • ์ƒํƒœ ๋ณ€๊ฒฝ์€ UI ์žฌ๊ตฌ์„ฑ ์œ ๋„
@Composable
fun TemperatureInput(viewModel: DemoViewModel = viewModel()) {
    TextField(
        value = viewModel.temperature,
        onValueChange = { viewModel.temperature = it }
    )
}

ViewModel๊ณผ Activity ์—ฐ๊ฒฐ

val demoViewModel: DemoViewModel by viewModels()



๐Ÿ’ ViewModel ํŠœํ† ๋ฆฌ์–ผ

MainActivity์—์„œ ViewModel ์ ‘๊ทผ

  • ViewModel์„ ํ†ตํ•ด ์ƒํƒœ ๋ฐ์ดํ„ฐ์— ์ ‘๊ทผํ•˜๊ณ , UI์™€ ์—ฐ๊ฒฐ
val viewModel: DemoViewModel by viewModels()

์˜จ๋„ ์ž…๋ ฅ ์ปดํฌ์ €๋ธ” ๊ตฌํ˜„

@Composable
fun TemperatureInput(viewModel: DemoViewModel) {
    Column {
        Text(text = "ํ˜„์žฌ ์˜จ๋„: ${viewModel.temperature}")
        TextField(
            value = viewModel.temperature,
            onValueChange = { viewModel.temperature = it },
            label = { Text("์˜จ๋„ ์ž…๋ ฅ") }
        )
    }
}



๐Ÿ’ ์•ˆ๋“œ๋กœ์ด๋“œ SQLite ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ฐœ์š”

๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์Šคํ‚ค๋งˆ

  • ํ…Œ์ด๋ธ”์˜ ๊ตฌ์กฐ ์ •์˜
  • ์—ด ์ด๋ฆ„, ํƒ€์ž…, ์ œ์•ฝ์กฐ๊ฑด ๋“ฑ์„ ํฌํ•จ
CREATE TABLE users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  age INTEGER
);

์—ด(Column), ํ–‰(Row), ๊ธฐ๋ณธ ํ‚ค

  • ์—ด: ์†์„ฑ (name, age ๋“ฑ)

  • ํ–‰: ๋ฐ์ดํ„ฐ ํ•œ ์ค„

  • ๊ธฐ๋ณธ ํ‚ค(PK): ๊ฐ ํ–‰์„ ๊ณ ์œ ํ•˜๊ฒŒ ์‹๋ณ„


SQLite์˜ ํŠน์ง•

  • ์•ˆ๋“œ๋กœ์ด๋“œ ๋‚ด์žฅ ๊ฒฝ๋Ÿ‰ DB

  • SQL๋กœ ๋ฐ์ดํ„ฐ ์กฐ์ž‘ ๊ฐ€๋Šฅ

  • Room ์—†์ด ์‚ฌ์šฉํ•˜๋ ค๋ฉด SQLiteOpenHelper ๊ตฌํ˜„ ํ•„์š”

Jetpack Room

SQLite ์‚ฌ์šฉ์„ ๊ฐ„ํŽธํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์ถ”์ƒํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ

  • @Entity: ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ ์ •์˜

  • @Dao: ์ฟผ๋ฆฌ ์ •์˜

  • @Database: DB ๊ฐ์ฒด ์ œ๊ณต



๐Ÿ’ RoomDemo ํŠœํ† ๋ฆฌ์–ผ

RoomDemo ํ”„๋กœ์ ํŠธ ๋งŒ๋“ค๊ธฐ

  • Gradle์— Room ์˜์กด์„ฑ ์ถ”๊ฐ€
implementation "androidx.room:room-runtime:2.6.1"
kapt "androidx.room:room-compiler:2.6.1"


์—”ํ‹ฐํ‹ฐ ๊ตฌ์ถ•

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

DAO ๊ตฌํ˜„

@Dao
interface NoteDao {
    @Insert suspend fun insert(note: Note)
    @Query("SELECT * FROM Note") fun getAll(): Flow<List<Note>>
}

Room DB ๊ฐ์ฒด ์ƒ์„ฑ

@Database(entities = [Note::class], version = 1)
abstract class NoteDatabase : RoomDatabase() {
    abstract fun noteDao(): NoteDao
}

ViewModel ์ถ”๊ฐ€

class NoteViewModel(private val repository: NoteRepository) : ViewModel() {
    val notes = repository.allNotes.asLiveData()

    fun addNote(content: String) {
        viewModelScope.launch {
            repository.insert(Note(content = content))
        }
    }
}


ViewModel: UI ์ƒํƒœ ๊ด€๋ฆฌ
LiveData / State: UI ์žฌ๊ตฌ์„ฑ ํŠธ๋ฆฌ๊ฑฐ
Room: ์•ˆ์ „ํ•˜๊ณ  ํŽธ๋ฆฌํ•œ DB ์ ‘๊ทผ
Compose: ์„ ์–ธํ˜• UI ์ž‘์„ฑ
=> ์ด ์กฐํ•ฉ์€ ํ˜„๋Œ€ ์•ˆ๋“œ๋กœ์ด๋“œ ๊ฐœ๋ฐœ์˜ ํ‘œ์ค€ ๊ตฌ์กฐ

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