μλλ‘μ΄λ μ ν리μΌμ΄μ κ°λ°μμ UI μν κ΄λ¦¬λ μ¬μ©μ κ²½νμ ν΅μ¬ μμλ€. νΉν, Jetpack Composeμ κ°μ μ μΈν UI νλ μμν¬μμλ μνμ μ΄λ²€νΈλ₯Ό λͺ νν κ΄λ¦¬νλ κ²μ΄ μ€μνλ€. μ΄λ₯Ό ν¨κ³Όμ μΌλ‘ ꡬννλ λ°©λ² μ€ νλκ° μν νλλ₯Ό νμ©νλ κ²μ΄λ€.
μνλ?
UIμ μν(State)λ μ¬μ©μμ μ λ ₯μ΄λ μΈλΆ λ°μ΄ν° λ³νμ λ°λΌ λ°λλ κ°μ΄λ€. μνλ UIλ₯Ό κ²°μ μ§λ μ€μν μμλ‘, μ μΈν UI νλ μμν¬μμλ μνκ° λ³κ²½λλ©΄ UIκ° μλμΌλ‘ μ λ°μ΄νΈλλ€.
μνμ μμ
- μ¬μ©μκ° λ²νΌμ λλ¬ λ‘λ© μ€ μνκ° νμ±νλ¨
- API μμ² ν λ°μ΄ν°λ₯Ό κ°μ Έμ νλ©΄μ νμ
- 체ν¬λ°μ€κ° μ νλμλμ§ μ¬λΆ
μ΄λ¬ν μνλ₯Ό ν¨κ³Όμ μΌλ‘ κ΄λ¦¬νκΈ° μν΄ μν νλκ° νμνλ€.
λ‘μ§μ΄λ?

UI μνλ μ μ μ΄μ§ μμΌλ©° μ ν리μΌμ΄μ μ λ°μ΄ν°λ μ¬μ©μ μ΄λ²€νΈμ λ°λΌ μκ°μ΄ μ§λλ©΄μ λ³κ²½λλ€. μ΄λ¬ν μν λ³κ²½μ μ²λ¦¬νλ λ‘μ§μ μνκ° λ³κ²½λλ μ΄μ μ μμ μ κ²°μ νλ©° UI μν μμ±μ μ€μν μν μ νλ€.
λ‘μ§μ λκ°μ§ μ ν
- λΉμ¦λμ€ λ‘μ§
- μ±μ λ°μ΄ν° μ²λ¦¬μ κ΄λ ¨λ λ‘μ§μΌλ‘, μλ₯Ό λ€μ΄ μ¬μ©μκ° λ²νΌμ ν΄λ¦νμ λ λ°μ΄ν°λ₯Ό μ μ₯νκ±°λ κ°±μ νλ μμ μ΄λ€.
- μ΄ λ‘μ§μ μ£Όλ‘ λλ©μΈ λλ λ°μ΄ν° λ μ΄μ΄μ λ°°μΉλλ©°, μν νλλ ν΄λΉ λ‘μ§μ μ²λ¦¬νλ€.
- UI λ‘μ§
- UI μνλ₯Ό νλ©΄μ νμνλ λ°©λ²μ κ΄λ ¨λ λ‘μ§μ΄λ€.
- μλ₯Ό λ€μ΄ μ¬μ©μκ° μΉ΄ν κ³ λ¦¬λ₯Ό μ ννμ λ μ μ ν κ²μμ°½ ννΈλ₯Ό νμνκ±°λ, λ²νΌ ν΄λ¦ μ λ€λ₯Έ νλ©΄μΌλ‘ νμνλ λ±μ μμ μ΄λ€.
μν νλ(State Holder)λ?
μν νλλ UI μνλ₯Ό μ μ₯νκ³ κ΄λ¦¬νλ μν μ νλ€. λ³΄ν΅ ViewModelμ΄ μ΄ μν μ μννλ©°, UIμ λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬νλ λ° λμμ μ€λ€. Jetpack Composeμμλ Composable ν¨μ λ΄λΆμμ μνλ₯Ό μ§μ κ΄λ¦¬νλ κ²½μ°λ μμ§λ§, μν νλλ₯Ό νμ©νλ©΄ μνλ₯Ό λ μμ μ μ΄κ³ μμΈ‘ κ°λ₯νκ² κ΄λ¦¬ν μ μλ€.
μν νλμ μ£Όμ μν
- μν(State) κ΄λ¦¬: UIκ° νμν λ°μ΄ν°λ₯Ό μ μ₯νκ³ μ μ§νλ€.
- μ΄λ²€νΈ μ²λ¦¬: μ¬μ©μ μ λ ₯ λ° λΉμ¦λμ€ λ‘μ§μ κ΄λ¦¬νλ€.
- κ΅¬μ± λ³κ²½ λμ: νλ©΄ νμ κ³Ό κ°μ κ΅¬μ± λ³κ²½(Configuration Change)μλ μνλ₯Ό μ μ§νλ€.
- UIμμ λΆλ¦¬: UIμ λ°μ΄ν° μ²λ¦¬λ₯Ό λΆλ¦¬νμ¬ μ μ§λ³΄μμ±μ λμΈλ€.
Android μλͺ μ£ΌκΈ°μ UI μν λ° λ‘μ§ μ ν
μλλ‘μ΄λμμ UI μνλ₯Ό ν¨κ³Όμ μΌλ‘ κ΄λ¦¬νλ €λ©΄ μλͺ μ£ΌκΈ°(Lifecycle)μ UI μνμ κ΄κ³λ₯Ό μ΄ν΄νλ κ²μ΄ μ€μνλ€. UI μν λ° λ‘μ§μ λ€μκ³Ό κ°μ μ νμΌλ‘ λλλ€.
1. UI μν μ ν
- μμ μν(Transient State): νλ©΄μλ§ μ‘΄μ¬νλ μν (μ: μ€ν¬λ‘€ μμΉ, μ λλ©μ΄μ μν)
- κ΅¬μ± λ³κ²½μ κ³ λ €ν μν(Configuration-resilient State): νλ©΄ νμ λ±μμλ μ μ§λλ μν (μ: ViewModelμμ κ΄λ¦¬νλ λ°μ΄ν°)
- μꡬ μν(Persistent State): μ±μ μ¬μμν΄λ μ μ§λλ μν (μ: SharedPreferences, Room λ°μ΄ν°λ² μ΄μ€)
2. UI λ‘μ§κ³Ό λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬
UI μ½λμ λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬νλ©΄ μ μ§λ³΄μμ±κ³Ό ν μ€νΈκ° μ¬μμ§λ€. μΌλ°μ μΌλ‘ λ€μκ³Ό κ°μ΄ ꡬμ±λλ€.
- UI λ‘μ§ (User Interface Logic): νλ©΄ ꡬμ±, μ λλ©μ΄μ , μ¬μ©μ μ λ ₯ μ²λ¦¬ (Compose UI λ΄λΆ)
- λΉμ¦λμ€ λ‘μ§ (Business Logic): λ°μ΄ν° μ²λ¦¬, λ€νΈμν¬ μμ², μν κ΄λ¦¬ (ViewModel, Repository, UseCase)
μ΄λ¬ν ꡬ쑰λ₯Ό λ°λ¦μΌλ‘μ¨ UI μνμ λ‘μ§μ 체κ³μ μΌλ‘ κ΄λ¦¬ν μ μλ€.
UI μν μμ± νμ΄νλΌμΈ
Jetpack Composeμμ UI μνλ₯Ό μμ±νλ κ³Όμ μ λ€μκ³Ό κ°μ΄ μ΄λ£¨μ΄μ§λ€.
- λ°μ΄ν° μμ€(Data Source): λ€νΈμν¬, λ°μ΄ν°λ² μ΄μ€, SharedPreferences λ±μ λ°μ΄ν° μ 곡
- μν νλ(State Holder, ViewModel): λ°μ΄ν°λ₯Ό μμ§νκ³ μνλ₯Ό κ΄λ¦¬
- UI μν λ³ν(State Transformation): λΉμ¦λμ€ λ°μ΄ν°λ₯Ό UIμμ μ¬μ©ν μνλ‘ λ³ν
- Composable UI: λ³νλ μνλ₯Ό νλ©΄μ λ λλ§
μ΄ νμ΄νλΌμΈμ ν΅ν΄ UI μνκ° μ²΄κ³μ μΌλ‘ μμ±λκ³ μ μ§λ μ μλ€.
μν νλμ ꡬ쑰 λ° λ¨λ°©ν₯ λ°μ΄ν° νλ¦(UDF)
Jetpack Composeλ λ¨λ°©ν₯ λ°μ΄ν° νλ¦(Unidirectional Data Flow, UDF)μ λ°λ₯Έλ€. μ¦, λ°μ΄ν°λ ν λ°©ν₯μΌλ‘ νλ₯΄λ©°, UIμμ λ°μν μ΄λ²€νΈλ λ€μ μν νλλ‘ μ λ¬λλ€.
λ¨λ°©ν₯ λ°μ΄ν° νλ¦μ ꡬ쑰
- ViewModel(State Holder) β μνλ₯Ό κ΄λ¦¬νκ³ UIκ° μ¬μ©ν λ°μ΄ν°λ₯Ό μ 곡
- Composable UI β μνλ₯Ό ꡬλ νκ³ UIλ₯Ό λ λλ§
- Event (μ¬μ©μ μ λ ₯) β UIμμ λ°μν μ΄λ²€νΈλ₯Ό μν νλλ‘ μ λ¬
μ΄λ₯Ό ν΅ν΄ UIμ μν κ΄λ¦¬ λ‘μ§μ΄ λΆλ¦¬λμ΄ μ½λμ μμΈ‘ κ°λ₯μ±κ³Ό μ μ§λ³΄μμ±μ΄ ν₯μλλ€.

μ κ·Έλ¦Όμ λ¨λ°©ν₯ λ°μ΄ν° νλ¦μμ μν νλ(ViewModel)μ μν μ΄λ€.
- UIλ ViewModelμ μνλ₯Ό ꡬλ νμ¬ νλ©΄μ λ λλ§νκ³ ,
- μ¬μ©μ μ λ ₯μ μ΄λ²€νΈ ννλ‘ μν νλμ μ λ¬νλ€.
- μν νλλ μ΄λ²€νΈλ₯Ό μ²λ¦¬νκ³ μλ‘μ΄ μνλ₯Ό μμ±νμ¬ UIμ λ°μνλ€.
μ΄ κ΅¬μ‘°λ₯Ό λ°λ₯΄λ©΄ UIμ μν λ³νκ° ν λ°©ν₯μΌλ‘λ§ νλ₯΄λ―λ‘ μμΈ‘ κ°λ₯μ±κ³Ό μ μ§λ³΄μμ±μ΄ ν₯μλλ€.
Jetpack Composeμμ μν νλ ꡬννκΈ°
Jetpack Composeμμλ μνλ₯Ό κ΄λ¦¬νλ μ¬λ¬ κ°μ§ λ°©λ²μ΄ μμ§λ§, ViewModelμ νμ©ν μν κ΄λ¦¬κ° κ°μ₯ μΌλ°μ μ΄λ€. μλ μ½λ μν νλλ₯Ό νμ©νλ λ°©λ²μ μμ μ΄λ€.
1. μν(State) λ°μ΄ν° ν΄λμ€ μ μ
UIμ νμν μνλ₯Ό νννλ λ°μ΄ν° ν΄λμ€λ₯Ό λ¨Όμ μ μνλ€.
data class UiState(
val isLoading: Boolean = false,
val text: String = "Hello, World!"
)
2. ViewModelμ μν νλλ‘ κ΅¬ν
ViewModelμ νμ©νμ¬ UI μνλ₯Ό κ΄λ¦¬νλ€.
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
fun onEvent(event: UiEvent) {
when (event) {
is UiEvent.ButtonClicked -> performAction()
}
}
private fun performAction() {
_uiState.update { currentState ->
currentState.copy(isLoading = true)
}
}
}
- MutableStateFlowλ₯Ό μ¬μ©νμ¬ μνλ₯Ό κ΄λ¦¬νλ€.
- onEvent() ν¨μλ₯Ό ν΅ν΄ UI μ΄λ²€νΈλ₯Ό μ²λ¦¬νκ³ μνλ₯Ό μ λ°μ΄νΈνλ€.
3. UIμμ μν κ΄μ°° λ° λ λλ§
Composable ν¨μμμ ViewModelμ ν΅ν΄ μνλ₯Ό ꡬλ νκ³ UIλ₯Ό ꡬμ±νλ€.
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Column {
Text(text = uiState.text)
Button(onClick = { viewModel.onEvent(UiEvent.ButtonClicked) }) {
Text("ν΄λ¦")
}
if (uiState.isLoading) {
CircularProgressIndicator()
}
}
}
- collectAsStateWithLifecycle()μ μ¬μ©νμ¬ μνλ₯Ό μμ νκ² κ΅¬λ νλ€.
- λ²νΌ ν΄λ¦ μ onEvent()λ₯Ό νΈμΆνμ¬ μνλ₯Ό λ³κ²½νλ€.
μν νλ μ¬μ©μ μ₯μ
- κ΅¬μ± λ³κ²½(Configuration Change) λμ
- ViewModelμ μ¬μ©νλ©΄ νλ©΄ νμ λ±μ κ΅¬μ± λ³κ²½μλ μνκ° μ μ§λλ€.
- UIμ λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬
- UIμμ μ§μ λ°μ΄ν°λ₯Ό μ²λ¦¬νμ§ μκ³ ViewModelμ΄ κ΄λ¦¬νλλ‘ νμ¬, μ μ§λ³΄μμ±κ³Ό ν μ€νΈ μ©μ΄μ±μ΄ ν₯μλλ€.
- μμΈ‘ κ°λ₯ν μν κ΄λ¦¬
- λ¨λ°©ν₯ λ°μ΄ν° νλ¦μ μ μ©νλ©΄ μνκ° ν λ°©ν₯μΌλ‘λ§ λ³κ²½λλ―λ‘, λλ²κΉ μ΄ μ¬μμ§κ³ λ²κ·Έκ° μ€μ΄λ λ€.
κ²°λ‘
- Jetpack Composeμμλ UI μνλ₯Ό λͺ ννκ² κ΄λ¦¬νλ κ²μ΄ μ€μνλ€.
- μν νλλ₯Ό νμ©νλ©΄ UIμ λ‘μ§μ λΆλ¦¬νκ³ , μνλ₯Ό μμΈ‘ κ°λ₯νκ² μ μ§ν μ μλ€.
- ViewModelμ μν νλλ‘ μ¬μ©νμ¬ μμ μ μΈ μν κ΄λ¦¬λ₯Ό ꡬννκ³ , λ¨λ°©ν₯ λ°μ΄ν° νλ¦μ λ°λ₯΄λ ꡬ쑰λ₯Ό μ μ©νλ©΄ μ μ§λ³΄μνκΈ° μ¬μ΄ μ½λμ λ λμ μ¬μ©μ κ²½νμ μ 곡ν μ μλ€
'π€ μλλ‘μ΄λ > μν€ν μ²' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[μλλ‘μ΄λ] UI μ΄λ²€νΈ (1) | 2025.03.29 |
---|---|
[μλλ‘μ΄λ] UI λ μ΄μ΄ μν€ν μ² (0) | 2025.03.28 |
[μλλ‘μ΄λ] μλλ‘μ΄λ μν€ν μ² κΆμ₯μ¬ν (0) | 2025.03.26 |
[μλλ‘μ΄λ] μλλ‘μ΄λ μ’ μ νλͺ© μ½μ (DI) (0) | 2025.03.25 |
[μλλ‘μ΄λ] Android 4λ μ»΄ν¬λνΈλ₯Ό 맀λνμ€νΈ μμ μ μΈνλ λ°©λ² (0) | 2025.03.24 |
μλλ‘μ΄λ μ ν리μΌμ΄μ κ°λ°μμ UI μν κ΄λ¦¬λ μ¬μ©μ κ²½νμ ν΅μ¬ μμλ€. νΉν, Jetpack Composeμ κ°μ μ μΈν UI νλ μμν¬μμλ μνμ μ΄λ²€νΈλ₯Ό λͺ νν κ΄λ¦¬νλ κ²μ΄ μ€μνλ€. μ΄λ₯Ό ν¨κ³Όμ μΌλ‘ ꡬννλ λ°©λ² μ€ νλκ° μν νλλ₯Ό νμ©νλ κ²μ΄λ€.
μνλ?
UIμ μν(State)λ μ¬μ©μμ μ λ ₯μ΄λ μΈλΆ λ°μ΄ν° λ³νμ λ°λΌ λ°λλ κ°μ΄λ€. μνλ UIλ₯Ό κ²°μ μ§λ μ€μν μμλ‘, μ μΈν UI νλ μμν¬μμλ μνκ° λ³κ²½λλ©΄ UIκ° μλμΌλ‘ μ λ°μ΄νΈλλ€.
μνμ μμ
- μ¬μ©μκ° λ²νΌμ λλ¬ λ‘λ© μ€ μνκ° νμ±νλ¨
- API μμ² ν λ°μ΄ν°λ₯Ό κ°μ Έμ νλ©΄μ νμ
- 체ν¬λ°μ€κ° μ νλμλμ§ μ¬λΆ
μ΄λ¬ν μνλ₯Ό ν¨κ³Όμ μΌλ‘ κ΄λ¦¬νκΈ° μν΄ μν νλκ° νμνλ€.
λ‘μ§μ΄λ?

UI μνλ μ μ μ΄μ§ μμΌλ©° μ ν리μΌμ΄μ μ λ°μ΄ν°λ μ¬μ©μ μ΄λ²€νΈμ λ°λΌ μκ°μ΄ μ§λλ©΄μ λ³κ²½λλ€. μ΄λ¬ν μν λ³κ²½μ μ²λ¦¬νλ λ‘μ§μ μνκ° λ³κ²½λλ μ΄μ μ μμ μ κ²°μ νλ©° UI μν μμ±μ μ€μν μν μ νλ€.
λ‘μ§μ λκ°μ§ μ ν
- λΉμ¦λμ€ λ‘μ§
- μ±μ λ°μ΄ν° μ²λ¦¬μ κ΄λ ¨λ λ‘μ§μΌλ‘, μλ₯Ό λ€μ΄ μ¬μ©μκ° λ²νΌμ ν΄λ¦νμ λ λ°μ΄ν°λ₯Ό μ μ₯νκ±°λ κ°±μ νλ μμ μ΄λ€.
- μ΄ λ‘μ§μ μ£Όλ‘ λλ©μΈ λλ λ°μ΄ν° λ μ΄μ΄μ λ°°μΉλλ©°, μν νλλ ν΄λΉ λ‘μ§μ μ²λ¦¬νλ€.
- UI λ‘μ§
- UI μνλ₯Ό νλ©΄μ νμνλ λ°©λ²μ κ΄λ ¨λ λ‘μ§μ΄λ€.
- μλ₯Ό λ€μ΄ μ¬μ©μκ° μΉ΄ν κ³ λ¦¬λ₯Ό μ ννμ λ μ μ ν κ²μμ°½ ννΈλ₯Ό νμνκ±°λ, λ²νΌ ν΄λ¦ μ λ€λ₯Έ νλ©΄μΌλ‘ νμνλ λ±μ μμ μ΄λ€.
μν νλ(State Holder)λ?
μν νλλ UI μνλ₯Ό μ μ₯νκ³ κ΄λ¦¬νλ μν μ νλ€. λ³΄ν΅ ViewModelμ΄ μ΄ μν μ μννλ©°, UIμ λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬νλ λ° λμμ μ€λ€. Jetpack Composeμμλ Composable ν¨μ λ΄λΆμμ μνλ₯Ό μ§μ κ΄λ¦¬νλ κ²½μ°λ μμ§λ§, μν νλλ₯Ό νμ©νλ©΄ μνλ₯Ό λ μμ μ μ΄κ³ μμΈ‘ κ°λ₯νκ² κ΄λ¦¬ν μ μλ€.
μν νλμ μ£Όμ μν
- μν(State) κ΄λ¦¬: UIκ° νμν λ°μ΄ν°λ₯Ό μ μ₯νκ³ μ μ§νλ€.
- μ΄λ²€νΈ μ²λ¦¬: μ¬μ©μ μ λ ₯ λ° λΉμ¦λμ€ λ‘μ§μ κ΄λ¦¬νλ€.
- κ΅¬μ± λ³κ²½ λμ: νλ©΄ νμ κ³Ό κ°μ κ΅¬μ± λ³κ²½(Configuration Change)μλ μνλ₯Ό μ μ§νλ€.
- UIμμ λΆλ¦¬: UIμ λ°μ΄ν° μ²λ¦¬λ₯Ό λΆλ¦¬νμ¬ μ μ§λ³΄μμ±μ λμΈλ€.
Android μλͺ μ£ΌκΈ°μ UI μν λ° λ‘μ§ μ ν
μλλ‘μ΄λμμ UI μνλ₯Ό ν¨κ³Όμ μΌλ‘ κ΄λ¦¬νλ €λ©΄ μλͺ μ£ΌκΈ°(Lifecycle)μ UI μνμ κ΄κ³λ₯Ό μ΄ν΄νλ κ²μ΄ μ€μνλ€. UI μν λ° λ‘μ§μ λ€μκ³Ό κ°μ μ νμΌλ‘ λλλ€.
1. UI μν μ ν
- μμ μν(Transient State): νλ©΄μλ§ μ‘΄μ¬νλ μν (μ: μ€ν¬λ‘€ μμΉ, μ λλ©μ΄μ μν)
- κ΅¬μ± λ³κ²½μ κ³ λ €ν μν(Configuration-resilient State): νλ©΄ νμ λ±μμλ μ μ§λλ μν (μ: ViewModelμμ κ΄λ¦¬νλ λ°μ΄ν°)
- μꡬ μν(Persistent State): μ±μ μ¬μμν΄λ μ μ§λλ μν (μ: SharedPreferences, Room λ°μ΄ν°λ² μ΄μ€)
2. UI λ‘μ§κ³Ό λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬
UI μ½λμ λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬νλ©΄ μ μ§λ³΄μμ±κ³Ό ν μ€νΈκ° μ¬μμ§λ€. μΌλ°μ μΌλ‘ λ€μκ³Ό κ°μ΄ ꡬμ±λλ€.
- UI λ‘μ§ (User Interface Logic): νλ©΄ ꡬμ±, μ λλ©μ΄μ , μ¬μ©μ μ λ ₯ μ²λ¦¬ (Compose UI λ΄λΆ)
- λΉμ¦λμ€ λ‘μ§ (Business Logic): λ°μ΄ν° μ²λ¦¬, λ€νΈμν¬ μμ², μν κ΄λ¦¬ (ViewModel, Repository, UseCase)
μ΄λ¬ν ꡬ쑰λ₯Ό λ°λ¦μΌλ‘μ¨ UI μνμ λ‘μ§μ 체κ³μ μΌλ‘ κ΄λ¦¬ν μ μλ€.
UI μν μμ± νμ΄νλΌμΈ
Jetpack Composeμμ UI μνλ₯Ό μμ±νλ κ³Όμ μ λ€μκ³Ό κ°μ΄ μ΄λ£¨μ΄μ§λ€.
- λ°μ΄ν° μμ€(Data Source): λ€νΈμν¬, λ°μ΄ν°λ² μ΄μ€, SharedPreferences λ±μ λ°μ΄ν° μ 곡
- μν νλ(State Holder, ViewModel): λ°μ΄ν°λ₯Ό μμ§νκ³ μνλ₯Ό κ΄λ¦¬
- UI μν λ³ν(State Transformation): λΉμ¦λμ€ λ°μ΄ν°λ₯Ό UIμμ μ¬μ©ν μνλ‘ λ³ν
- Composable UI: λ³νλ μνλ₯Ό νλ©΄μ λ λλ§
μ΄ νμ΄νλΌμΈμ ν΅ν΄ UI μνκ° μ²΄κ³μ μΌλ‘ μμ±λκ³ μ μ§λ μ μλ€.
μν νλμ ꡬ쑰 λ° λ¨λ°©ν₯ λ°μ΄ν° νλ¦(UDF)
Jetpack Composeλ λ¨λ°©ν₯ λ°μ΄ν° νλ¦(Unidirectional Data Flow, UDF)μ λ°λ₯Έλ€. μ¦, λ°μ΄ν°λ ν λ°©ν₯μΌλ‘ νλ₯΄λ©°, UIμμ λ°μν μ΄λ²€νΈλ λ€μ μν νλλ‘ μ λ¬λλ€.
λ¨λ°©ν₯ λ°μ΄ν° νλ¦μ ꡬ쑰
- ViewModel(State Holder) β μνλ₯Ό κ΄λ¦¬νκ³ UIκ° μ¬μ©ν λ°μ΄ν°λ₯Ό μ 곡
- Composable UI β μνλ₯Ό ꡬλ νκ³ UIλ₯Ό λ λλ§
- Event (μ¬μ©μ μ λ ₯) β UIμμ λ°μν μ΄λ²€νΈλ₯Ό μν νλλ‘ μ λ¬
μ΄λ₯Ό ν΅ν΄ UIμ μν κ΄λ¦¬ λ‘μ§μ΄ λΆλ¦¬λμ΄ μ½λμ μμΈ‘ κ°λ₯μ±κ³Ό μ μ§λ³΄μμ±μ΄ ν₯μλλ€.

μ κ·Έλ¦Όμ λ¨λ°©ν₯ λ°μ΄ν° νλ¦μμ μν νλ(ViewModel)μ μν μ΄λ€.
- UIλ ViewModelμ μνλ₯Ό ꡬλ νμ¬ νλ©΄μ λ λλ§νκ³ ,
- μ¬μ©μ μ λ ₯μ μ΄λ²€νΈ ννλ‘ μν νλμ μ λ¬νλ€.
- μν νλλ μ΄λ²€νΈλ₯Ό μ²λ¦¬νκ³ μλ‘μ΄ μνλ₯Ό μμ±νμ¬ UIμ λ°μνλ€.
μ΄ κ΅¬μ‘°λ₯Ό λ°λ₯΄λ©΄ UIμ μν λ³νκ° ν λ°©ν₯μΌλ‘λ§ νλ₯΄λ―λ‘ μμΈ‘ κ°λ₯μ±κ³Ό μ μ§λ³΄μμ±μ΄ ν₯μλλ€.
Jetpack Composeμμ μν νλ ꡬννκΈ°
Jetpack Composeμμλ μνλ₯Ό κ΄λ¦¬νλ μ¬λ¬ κ°μ§ λ°©λ²μ΄ μμ§λ§, ViewModelμ νμ©ν μν κ΄λ¦¬κ° κ°μ₯ μΌλ°μ μ΄λ€. μλ μ½λ μν νλλ₯Ό νμ©νλ λ°©λ²μ μμ μ΄λ€.
1. μν(State) λ°μ΄ν° ν΄λμ€ μ μ
UIμ νμν μνλ₯Ό νννλ λ°μ΄ν° ν΄λμ€λ₯Ό λ¨Όμ μ μνλ€.
data class UiState(
val isLoading: Boolean = false,
val text: String = "Hello, World!"
)
2. ViewModelμ μν νλλ‘ κ΅¬ν
ViewModelμ νμ©νμ¬ UI μνλ₯Ό κ΄λ¦¬νλ€.
class MyViewModel : ViewModel() {
private val _uiState = MutableStateFlow(UiState())
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
fun onEvent(event: UiEvent) {
when (event) {
is UiEvent.ButtonClicked -> performAction()
}
}
private fun performAction() {
_uiState.update { currentState ->
currentState.copy(isLoading = true)
}
}
}
- MutableStateFlowλ₯Ό μ¬μ©νμ¬ μνλ₯Ό κ΄λ¦¬νλ€.
- onEvent() ν¨μλ₯Ό ν΅ν΄ UI μ΄λ²€νΈλ₯Ό μ²λ¦¬νκ³ μνλ₯Ό μ λ°μ΄νΈνλ€.
3. UIμμ μν κ΄μ°° λ° λ λλ§
Composable ν¨μμμ ViewModelμ ν΅ν΄ μνλ₯Ό ꡬλ νκ³ UIλ₯Ό ꡬμ±νλ€.
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
Column {
Text(text = uiState.text)
Button(onClick = { viewModel.onEvent(UiEvent.ButtonClicked) }) {
Text("ν΄λ¦")
}
if (uiState.isLoading) {
CircularProgressIndicator()
}
}
}
- collectAsStateWithLifecycle()μ μ¬μ©νμ¬ μνλ₯Ό μμ νκ² κ΅¬λ νλ€.
- λ²νΌ ν΄λ¦ μ onEvent()λ₯Ό νΈμΆνμ¬ μνλ₯Ό λ³κ²½νλ€.
μν νλ μ¬μ©μ μ₯μ
- κ΅¬μ± λ³κ²½(Configuration Change) λμ
- ViewModelμ μ¬μ©νλ©΄ νλ©΄ νμ λ±μ κ΅¬μ± λ³κ²½μλ μνκ° μ μ§λλ€.
- UIμ λΉμ¦λμ€ λ‘μ§μ λΆλ¦¬
- UIμμ μ§μ λ°μ΄ν°λ₯Ό μ²λ¦¬νμ§ μκ³ ViewModelμ΄ κ΄λ¦¬νλλ‘ νμ¬, μ μ§λ³΄μμ±κ³Ό ν μ€νΈ μ©μ΄μ±μ΄ ν₯μλλ€.
- μμΈ‘ κ°λ₯ν μν κ΄λ¦¬
- λ¨λ°©ν₯ λ°μ΄ν° νλ¦μ μ μ©νλ©΄ μνκ° ν λ°©ν₯μΌλ‘λ§ λ³κ²½λλ―λ‘, λλ²κΉ μ΄ μ¬μμ§κ³ λ²κ·Έκ° μ€μ΄λ λ€.
κ²°λ‘
- Jetpack Composeμμλ UI μνλ₯Ό λͺ ννκ² κ΄λ¦¬νλ κ²μ΄ μ€μνλ€.
- μν νλλ₯Ό νμ©νλ©΄ UIμ λ‘μ§μ λΆλ¦¬νκ³ , μνλ₯Ό μμΈ‘ κ°λ₯νκ² μ μ§ν μ μλ€.
- ViewModelμ μν νλλ‘ μ¬μ©νμ¬ μμ μ μΈ μν κ΄λ¦¬λ₯Ό ꡬννκ³ , λ¨λ°©ν₯ λ°μ΄ν° νλ¦μ λ°λ₯΄λ ꡬ쑰λ₯Ό μ μ©νλ©΄ μ μ§λ³΄μνκΈ° μ¬μ΄ μ½λμ λ λμ μ¬μ©μ κ²½νμ μ 곡ν μ μλ€
'π€ μλλ‘μ΄λ > μν€ν μ²' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
[μλλ‘μ΄λ] UI μ΄λ²€νΈ (1) | 2025.03.29 |
---|---|
[μλλ‘μ΄λ] UI λ μ΄μ΄ μν€ν μ² (0) | 2025.03.28 |
[μλλ‘μ΄λ] μλλ‘μ΄λ μν€ν μ² κΆμ₯μ¬ν (0) | 2025.03.26 |
[μλλ‘μ΄λ] μλλ‘μ΄λ μ’ μ νλͺ© μ½μ (DI) (0) | 2025.03.25 |
[μλλ‘μ΄λ] Android 4λ μ»΄ν¬λνΈλ₯Ό 맀λνμ€νΈ μμ μ μΈνλ λ°©λ² (0) | 2025.03.24 |