ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • (기초) 1-7. ViewModel 사용
    안드로이드 학습/Compose 2025. 9. 16. 17:10

    ViewModel은 개념상으로 AAC의 ViewModel과 MVVM의 개념은 다르다. 

     

    여기서는 2 개념을 합쳐서 

     

    AAC ViewModel - 화면 회전/구성 변경(config change)에도 데이터를 유지하는 부분과

    MVVM ViewModel의 UI에서 사용되는 데이터 관리 및 UI의 비지니스 로직을 포함한다.

    상태 보존 화면 회전등에도 데이터 유지
    로직 분리 UI 코드와 비지니스 로직 분리
    수명 보장 Activity/Fragment보다 긴 수명주기 

     

    예제:

     

     

     

    1. ViewModel 호출

        val viewModel: CounterViewModel = viewModel()
    • Activity에서 ViewModel을 선언하는 방법이다. by viewModels()를 사용하면 Lifecycler에 따라 자동으로 관리 된다. 

    2. 데이터 관리 :

     

    데이터 부분은 stateOf를 사용한 예제도 있고 stateFlow를 사용한 예제도 있어서 무슨 차이인지를 언급하고 넘어가야 할 듯 싶다. 

     

    stateOf 

    • Compose 전용 상태 홀더이다.
    • 단일 값 상태를 저장하고, 값이 바뀌면 Compose가 자동으로 Recomposition을 수행.

    stateFlow

    • Kotlin Flow 기반 상태 홀더이다.
    • 비동기/스트림 처리에 적합하다.
    • Compose에서 사용하려면 collectAsState()로 변환해야 Recomposition 가능하다. 

    chatgpt의 따르면 stateOf를 ViewModel에서 사용한다면

    • ViewModel은 Compose가 없는 상황에서도 사용될 수 도 있다.
    • 아키텍처 관점에서도 ViewModel과 UI의 독립적인 관리가 필요한데 Compose 전용 도구를 사용하면 결합도가 올라간다. 

     

    이러한 이유에서 stateFlow 사용.

    // 선언
    private val _count = MutableStateFlow(0)
    val count: StateFlow<Int> = _count
    
    // 호출
    val count by viewModel.count.collectAsState()

     

    3. 전체 코드 

     

    ViewModel

    class CounterViewModel : ViewModel() {
        private val _count = MutableStateFlow(0)
        val count: StateFlow<Int> = _count
    
        fun increment() {
            _count.value += 1
        }
    
        fun decrement() {
            _count.value -= 1
        }
    
        fun reset() {
            _count.value = 0
        }
    }

     

    Screen

    @Composable
    fun CounterScreen(viewModel: CounterViewModel = viewModel()) {
        // StateFlow를 Compose 상태로 변환
        val count by viewModel.count.collectAsState()
    
        Column(
            modifier = Modifier
                .fillMaxSize()
                .padding(32.dp),
            verticalArrangement = Arrangement.Center,
            horizontalAlignment = Alignment.CenterHorizontally
        ) {
            Text("Count: $count", style = MaterialTheme.typography.headlineMedium)
    
            Spacer(modifier = Modifier.height(24.dp))
    
            Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
                Button(onClick = { viewModel.increment() }) {
                    Text("Increment")
                }
                Button(onClick = { viewModel.decrement() }) {
                    Text("Decrement")
                }
                Button(onClick = { viewModel.reset() }) {
                    Text("Reset")
                }
            }
        }
    }
Designed by Tistory.