최근 안드로이드에서는 View에 State를 제공하는 형태로 UI에 데이터를 보여주고 있습니다. 이때, 상태를 제공하는 방법으로는 크게 2가지로 나뉘게 됩니다. 바로, Single State와 Multiple State입니다. 각 방법마다 장단점이 존재하고 어려운 개념이 아니기에 코드 예제와 함께 설명하겠습니다.
먼저, 아래의 3개의 변수가 필요한 상황이라고 가정하겠습니다.
- 제목
- 내용
- 체크박스
1. Single State를 사용한 경우
Single State는 하나의 data class로 묶어서 처리하는 것을 뜻합니다. 제목, 내용, 체크박스 상태를 관리하기 위해서 아래처럼 CardUiState라는 data class를 만듭니다.
data class CardUiState(
val title: String = "",
val description: String = "",
val checked: Boolean = false
)
그리고 ViewModel에서 해당 data class를 사용하기 위해서 MutableStateOf로 선언합니다. MutableStateOf의 value 프로퍼티를 통해 데이터를 읽고 저장할 수 있습니다. 상태 변화를 확인하기 위한 generateRandomData() 함수도 만들었습니다. 해당 함수는 CardUiState의 값을 변경하는 역할을 합니다. 버튼을 눌렀을 때, 해당 함수가 실행돼서 UI의 모습이 변하는지 확인하기 위해 만들었습니다.
@HiltViewModel
class SingleMultipleStateViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) : ViewModel() {
private val _cardState = mutableStateOf(CardUiState())
val cardState: State<CardUiState> = _cardState
init {
_cardState.value = CardUiState(
title = "title",
description = "description",
checked = true
)
}
fun generateRandomData() {
val randomTitles = listOf("Sunshine", "Rainforest", "Ocean Breeze", "Mountain Peak", "City Lights")
val randomDescriptions = listOf(
"A bright, cheerful day with warm sunlight.",
"A dense, mysterious jungle filled with wildlife.",
"A gentle sea breeze with waves lapping at the shore.",
"A stunning view from the top of a high mountain.",
"The vibrant life and energy of a bustling city."
)
_cardState.value = _cardState.value.copy(
title = randomTitles.random(),
description = randomDescriptions.random(),
checked = true
)
}
}
이렇게 상태와 관련된 변수를 data class로 관리하기 때문에 상태를 언제든지 한 곳에서 확인할 수 있게 됩니다.
1-1. Single State의 장점
- 화면의 상태를 한 곳에서 확인할 수 있어서 편하고 가독성이 좋습니다.
- 상태에 대한 테스트를 작성하기 쉬워집니다.
1-2. Single State의 단점
- 위의 코드 예시에 나온 것처럼 하나의 필드만 수정되는 경우에도 모든 필드를 복사해야 합니다.
2. Multiple State를 사용한 경우
이번에는 Multiple State 방식을 사용해서 위에서 보인 예제를 변경하겠습니다. Multiple State는 각 상태를 하나의 data class로 관리하는 것이 아니라 모든 필드가 ViewModel 내부에 선언돼 있는 구조입니다. 아래 코드는 Multiple State 방식으로 변경한 모습입니다.
@HiltViewModel
class SingleMultipleStateViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
) : ViewModel() {
// Multiple State
private val _title = mutableStateOf("")
val title: State<String> = _title
private val _description = mutableStateOf("")
val description: State<String> = _description
private val _checked = mutableStateOf(true)
val checked: State<Boolean> = _checked
init {
_title.value = "title"
_description.value = "description"
_checked.value = true
}
fun generateRandomData() {
val randomTitles = listOf("Sunshine", "Rainforest", "Ocean Breeze", "Mountain Peak", "City Lights")
val randomDescriptions = listOf(
"A bright, cheerful day with warm sunlight.",
"A dense, mysterious jungle filled with wildlife.",
"A gentle sea breeze with waves lapping at the shore.",
"A stunning view from the top of a high mountain.",
"The vibrant life and energy of a bustling city."
)
_title.value = randomTitles.random()
_description.value = randomDescriptions.random()
_checked.value = true
}
}
2-1. Multiple State의 장점
- 각 필드가 서로 의존성을 띄지 않고 독립적으로 작동됩니다.
- 하나의 필드만 변경될 때, 다른 필드는 변경되지 않습니다.
2-2. Multiple State의 단점
- 일관성 없게 변수를 선언하면 순서가 섞이는 등 가독성이 안 좋아질 수 있습니다.
- 필드가 많은 경우 파악하기가 어렵습니다.
3. 결론
안드로이드에서 State를 관리할 때 ViewModel 내부에서 Single State, Multiple State 2가지 방법을 사용할 수 있습니다. 사용자 입장에서도 동일한 결과를 보여주지만, 코드 관리의 측면에서는 다른 양상을 보입니다. 저는 두 가지 방법 모두 사용해 보았는데 연관된 필드가 3개 이상으로 많아질 때는 Single State 방식을 더 선호합니다.
여러분의 생각과 사례를 댓글로 공유해 주시는건 언제든지 환영합니다.
추가사항: 이 예제에서는 다중 스레드에 의해 State가 동시에 수정되면 발생할 수 있는 크리티컬 섹션(Critical Section) 위험성이 존재하는데 다음 포스팅에서 설명하겠습니다.
'안드로이드 > Compose State' 카테고리의 다른 글
[안드로이드 Jetpack Compose] remember와 MutableState의 3가지 사용 방법 (0) | 2024.03.16 |
---|