MVI에서 다루는 State의 immutable에 대해 이번 포스팅에서 다뤄보고자 합니다.
MVI의 State는 반드시 immutable해야한다.
→ MVI에서 State는 immutable해야하고, 모든 상태 변경은 .copy를 통해 수행되어야 한다.
왜 immutable해야할까?
1. Compose는 값이 변경되었는지를 기준으로 U를 그린다.
Compose는 내부적으로 eqauls()또는 reference 비교로 변화 여부를 감지한다.
mutable상태 (var, val 내부 값 변경)는 변경을 감지하지 못해 재조합이 안일어날 수 있다.
mutable 상태 예시
data class LoginState(
val email: StringBuilder = StringBuilder(), //mutable 객체
)
email.append(…) 처럼 내부 상태만 바꾸면, equals()는 동일 객체로 간주하기 때문에, Compose는 변화로 인식을 못한다
→ Compose가 변화를 인식하지 못하면 UI recomposition도 안 일어난다!
2. Immutable 객체는 추론과 테스트가 쉽다.
- 상태 변경 전, 후가 분명하게 처리된다.
- 디버깅할 때 어떤 인텐트가 어떤 상태를 유발했는지 로그로 추적하기가 쉽다.
- 테스트 코드에서 assertEquals(expected, actual)로 비교가 쉽다.
3. 동시성 문제를 방지할 수 있다.
동시성 문제란?
→ 여러 작업(코루틴, 스레드)이 동시에 하나의 상태를 변경하거나 읽으려고할 때 발생하는 오류이다.
위험상황 예시
data class MutableState(
var counter: Int
)
val sharedState = MutableState(0)
viewModelScope.launch {
sharedState.counter += 1 // 코루틴 A
}
viewModelScope.launch {
sharedState.counter += 1 // 코루틴 B
}
두 코루틴이 같은 객체(sharedState)의 내부 값을 동시에 바꾸면,
덮어쓰기(Race condition), 잘못된 결과, 충돌이 발생할 수 있다.
- 따라서 viewModel에서 상태 변경할 때 MutableStateFlow를 사용한다.
- 만약 상태가 불변이면, 코루틴 간 동시 접근도 안전하게 처리된다.
- 하지만 내부가 가변 객체이면, 여러 코루틴이 같은 객체를 참조하므로 동기화 이슈가 발생할 수 있다.
State는 어떻게 구현하면 안전할까?
State 선언
data class LoginState(
val email: String = "",
val password: String = "",
val isLoading: Boolean = false,
val errorMessage: String? = null
)
ViewModel 내부에서는 .copy활용
_state.update { current ->
current.copy(
email = intent.value,
errorMessage = null
)
}
- 이 코드는 LoginState 객체를 복사하면서 일부 필드만 변경한다.
- Compose는 새로운 객체로 감지 → recomposition 일어남
.copy메서드는
- kotlin의 data class는 자동으로 .copy()메서드를 제공한다.
- .copy()는 원래 겍체를 복사하면서, 특정 속성만 변경한 새로운 객체를 만드는 함수이다.
- 상태를 직접 변경하면 Compose가 감지하지 못하기 때문에, .copy()로 변경이 필요한 필드만 바꾸고, 새로운 객체를 만들어 emit할 수 있다.
Compose의 equals()비교
val old = LoginState(email = "a")
val new = old.copy(email = "b")
println(old == new) // false → Compose는 재조합 발생시킴
즉 data class, copy구조가 Compose와 연결되어있다.
'Android > 공부' 카테고리의 다른 글
| [Android/공부] NDK(네이티브 개발 키트) 사용과 ABI 빌드 환경 톺아보기 (1) | 2024.11.14 |
|---|---|
| [Android/공부] Compose로 UI 적용기 -1 (0) | 2024.10.14 |
| [Android] MockWebServer란? : okhttp mockwebserver (0) | 2024.09.25 |
| [Android] MockWebServer로 Mock API 활용하기 (2) | 2024.09.25 |
| [Android] XML 과 Compose 렌더링 방식의 차이 (0) | 2024.09.23 |