안드로이드 개발에서 제트팩 컴포즈(Jetpack Compose)는 UI를 구축하는 현대적인 방식을 제공합니다. 특히 상태 관리는 컴포즈 애플리케이션에서 중요한 부분인데, 이를 효과적으로 관리하기 위해 ViewModel과 함께 collectAsState()를 사용하는 방법을 알아보겠습니다.
collectAsState()는 Jetpack Compose에서 Flow(또는 StateFlow)를 쉽게 구독하고, 구독 결과를 Compose의 State로 변환해주는 확장 함수입니다. 이 함수를 사용하면 Flow가 새 값을 emit할 때마다 UI가 자동으로 재컴포지션되어 최신 상태를 표시해줍니다.
State) 변화를 관찰해 UI를 업데이트합니다.collectAsState()를 사용하면 Flow를 직접 launch해서 collect할 필요 없이, 자동으로 Flow를 구독하며 현재 값을 Compose 상태로 변환해 줍니다.class MainViewModel : ViewModel() {
private val _uiState = MutableStateFlow(MyUiState())
val uiState: StateFlow<MyUiState> = _uiState.asStateFlow()
fun updateSomething(newValue: String) {
_uiState.update { currentState ->
currentState.copy(something = newValue)
}
}
}
MutableStateFlow : 내부에서 변경 가능한 상태 정의StateFlow로 : 외부에는 읽기 전용@Composable
fun MainScreen(viewModel: MainViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsState()
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column {
Text(text = "Current value: ${uiState.something}")
Button(onClick = { viewModel.updateSomething("New Value") }) {
Text("Update Value")
}
if (uiState.isLoading) {
CircularProgressIndicator()
}
uiState.error?.let { error ->
Text(
text = error,
color = MaterialTheme.colorScheme.error
)
}
}
}
}
uiState : Flow를 State로 변환이제 uiState는 State 타입으로,
viewModel.uiState의 값이 변경될 때마다 이 컴포저블이 재구성됩니다
@Composable
fun MainScreen(viewModel: MainViewModel = viewModel()) {
var uiState by remember { mutableStateOf(MyUiState()) }
LaunchedEffect(viewModel) {
viewModel.uiState.collect { newState ->
uiState = newState
}
}
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Column {
Text(text = "Current value: ${uiState.something}")
Button(onClick = { viewModel.updateSomething("New Value") }) {
Text("Update Value")
}
if (uiState.isLoading) {
CircularProgressIndicator()
}
uiState.error?.let { error ->
Text(
text = error,
color = MaterialTheme.colorScheme.error
)
}
}
}
}
val state1 by flow1.collectAsState()
val state2 by flow2.collectAsState()
val state3 by flow3.collectAsState()
var state1 by remember { mutableStateOf(initialValue1) }
var state2 by remember { mutableStateOf(initialValue2) }
var state3 by remember { mutableStateOf(initialValue3) }
LaunchedEffect(Unit) {
launch { flow1.collect { state1 = it } }
launch { flow2.collect { state2 = it } }
launch { flow3.collect { state3 = it } }
}
val state by flow.collectAsState(initial = initialValue)
var state by remember { mutableStateOf(initialValue) }
LaunchedEffect(Unit) {
flow.collect { state = it }
}
LaunchedEffect(Unit) {
try {
flow.collect { state = it }
} catch (e: Exception) {
// error
}
}
메모리 사용: 두 방식 모두 비슷한 메모리 사용량을 보이지만 collectAsState()는 내부적으로 최적화되어 있어 약간 더 효율적일 수 있습니다.
재구성 효율성: collectAsState()는 Compose의 상태 시스템과 긴밀하게 통합되어 변경된 부분만 효율적으로 재구성합니다.
개발자 효율성: collectAsState()를 사용하면 개발자는 보일러플레이트 코드를 줄이고 핵심 비즈니스 로직에 집중할 수 있습니다.
collectAsState(context = ...)로도 가능합니다)collectAsState()는 제트팩 컴포즈에서 Flow를 관찰하는 가장 간결하고 효율적인 방법입니다. 기존의 방식과 비교했을 때 코드가 더 간결해지고 생명주기 관리가 자동으로 이루어지며 여러 Flow를 쉽게 처리할 수 있다는 장점이 있습니다.
그러나 특별한 요구사항이 있는 경우 전통적인 방식을 사용하여 Flow 수집에 대한 더 세밀한 제어가 가능합니다. 각 방식의 장단점을 이해하고 상황에 맞게 선택하는 것이 중요 한 것 같습니다.