Kotlin (안드로이드 Compose)

Jetpack Compose에서 상태 관리하기: remember, Flow, StateFlow

duduryapp 2025. 3. 20. 08:22

Jetpack Compose는 선언형 UI 프레임워크로, 상태(state)를 효율적으로 관리하는 것이 매우 중요합니다. Compose에서 자주 사용되는 remember, Flow, StateFlow를 비교하며 각각의 역할과 활용 방법을 알아보겠습니다.

1. remember란?

remember는 컴포저블 함수에서 상태를 유지하는 데 사용됩니다. 특정 값이 재구성(Recomposition)될 때 초기화되지 않도록 저장하는 역할을 합니다.

 

@Composable
fun Counter() {
    var count by remember { mutableStateOf(0) }

    Column {
        Text(text = "Count: $count")
        Button(onClick = { count++ }) {
            Text("Increase")
        }
    }
}

remember 사용 예시

위 코드에서 count remember를 통해 유지되므로, 버튼을 클릭할 때마다 증가한 상태가 유지됩니다.

하지만 remember는 화면 회전과 같은 구성 변경(Configuration Change) 시 상태가 유지되지 않습니다. 이를 해결하려면 rememberSaveable을 사용해야 합니다.

2. Flow란?

Flow는 Kotlin의 코루틴을 활용한 비동기 데이터 스트림입니다. 지속적으로 변경되는 데이터를 처리하는 데 유용하며, LiveData와 유사하지만 더 강력한 기능을 제공합니다.

Flow 사용 예시

 

fun timerFlow(): Flow<Int> = flow {
    var count = 0
    while (true) {
        emit(count++) 
        delay(1000L) // 1초마다 값 방출
    }
}

위 코드는 매초 증가하는 숫자를 방출하는 Flow입니다. Compose에서 Flow를 UI와 연결하려면 collectAsState를 사용할 수 있습니다.

 

@Composable
fun TimerScreen() {
    val count by timerFlow().collectAsState(initial = 0)

    Text(text = "Timer: $count")
}

3. StateFlow란?

StateFlow Flow의 일종으로, 상태를 저장하고 변경이 발생할 때 최신 값을 방출하는 특성을 가집니다. LiveData와 비슷하지만 코루틴 친화적인 방식으로 동작합니다.

StateFlow 사용 예시

 

class TimerViewModel : ViewModel() {
    private val _timer = MutableStateFlow(0)
    val timer: StateFlow<Int> = _timer

    init {
        viewModelScope.launch {
            while (true) {
                _timer.value += 1
                delay(1000L)
            }
        }
    }
}

ViewModel에서 StateFlow를 정의하고 관리할 수 있습니다.

Compose에서 이를 구독하려면 collectAsState()를 사용합니다.

 

@Composable
fun TimerScreen(viewModel: TimerViewModel = viewModel()) {
    val count by viewModel.timer.collectAsState()

    Text(text = "Timer: $count")
}

결론

Jetpack Compose에서 상태 관리는 매우 중요합니다. remember는 간단한 UI 상태를 유지하는 데 유용하고, Flow는 비동기 데이터 스트림을 처리할 때 적합합니다. StateFlow Flow를 기반으로 최신 상태를 보장하면서도 ViewModel과 함께 사용하기 좋아 LiveData를 대체할 수 있는 강력한 옵션입니다.