안녕하세요. 중곰입니다.
오늘은 ViewModel에서 데이터 처리 시 변경 데이터를
어떻게 관찰하고 동작하는지를 볼 수 있는
LiveData와 StateFlow를 살펴볼려고 합니다.
개념 정도를 살펴보면서 어떤 형태이며
언제 사용하면 좋은지까지 살펴보려 합니다.
먼저 LiveData와 StateFlow에 대해 간단히 살펴 봅니다.
LiveData?
- LiveData
- 관찰 가능한 데이터 홀더 클래스이며, 수명주기를 인식함
- 액티비티, 프래그먼트, 서비스 등 다른 앱 구성요소의 수명 주기를 고려
- 수명 주기 인식을 통해 LiveData는 활동 수명 주기 상태에 있는 앱 구성요소 관찰자만 업데이트
- 쉽게 말해 데이터가 변경될 때 화면을 자동으로 업데이트해주는 마법 상자
- Observer 클래스
- 관찰자의 수명주기가 STARTED or RESUMED 상태일때 LiveData 관찰자를 활성 상태로 간주
- 활성 관찰자에게만 업데이트 정보 알림
- LifeCycleOwner 인터페이스를 구현하는 객체와 페이링된 관찰자를 등록 할 수 있음
- 관찰자에 대응되는 Lifecycle 객체의 상태가 DESTORYED 시 관찰자를 삭제 할 수 있음
- 액티비티와 프래그먼트는 LiveData 객체를 안전하게 관찰
- 수명주기가 끝나는 즉시 수신 거부되어 누수를 걱정하지 않아도 됨
- 간단한 예시
- 특징
- Observer 패턴을 기반으로 동작
- 항상 최신 데이터만 유지
- 안드로이드 생명주기와 통합
- 자동으로 메모리 누수 방지
- 장점
- 생명주기 자동 관리 (메모리 누수 걱정 없음)
- 설정 변경(화면 회전 등) 자동 처리
- 안드로이드 플랫폼과의 완벽한 통합
- 간단한 구현
- 단점
- 메인 스레드에서만 값 변경 가능
- 코루틴 지원 제한적
- 안드로이드 플랫폼 의존적
class MainViewModel : ViewModel() {
// LiveData 생성되며, 내부에서만 변경 가능
private val _count = MutableLiveData<Int>(0)
// LiveData 외부에 노출되는 읽기 전용
val count: LiveData<Int> = _count
fun increment() {
_count.value = (_count.value ?: 0) + 1
}
}
// Activity/Fragment에서
viewModel.count.observe(viewLifecycleOwner) { count ->
textView.text = count.toString()
}
StateFlow
- 현재 상태와 새로운 상태 업데이트를 수집기에 내보내는 관찰 가능한 상태 홀더 흐름
- value 속서을 통해서도 현재 상태를 값을 읽을 수 있음
- 상태를 업데이트하고 흐름을 전송하려면 MutableStateFlow 클래스의 value 속성에 새 값을 할당
- 쉽게 보면, LiveData의 “업그레이드 버전” 이라 생각하면 되는데, 코루틴 기반의 핫 스트림으로 동작하는 상태 홀더
- 간단한 예시
class MainViewModel : ViewModel() {
private val _count = MutableStateFlow<Int>(0)
val count: StateFlow<Int> = _count.asStateFlow()
fun increment() {
viewModelScope.launch {
_count.value = _count.value + 1
}
}
}
// Activity/Fragment에서
lifecycleScope.launch {
viewModel.count.collect { count ->
textView.text = count.toString()
}
}
- 특징
- Hot Stream (구독자가 없어도 데이터 발행)
- 항상 값을 가짐 (null 불가)
- 중복 값 발행
- distinctUntilChanged() 내장
- 장점
- 코루틴과 완벽한 통합
- 백그라운드 스레드에서 값 변경 가능
- Flow 연산자 사용 가능 (map, filter 등)
- 플랫폼 독립적
- Hot Stream (항상 최신 값 유지)
- 단점
- 생명주기 수동 관리 필요
- 초기값 필수
- LiveData보다 약간 복잡한 설정
🤔 뭘 써야할까요?
LiveData를 쓰면 좋을 때
- 간단한 화면 업데이트가 필요할 때
- 생명주기 관리를 자동으로 하고 싶을 때
- 기존 안드로이드 앱을 유지보수할 때
StateFlow를 쓰면 좋을 때
- 복잡한 데이터 처리가 필요할 때
- 백그라운드 작업이 많을 때
- 최신 안드로이드 기술을 사용하고 싶을 때
개인적 생각으로 사용 추천한다면?
- 단순 UI 상태 관리: LiveData
- 복잡한 데이터 스트림/비동기 처리: StateFlow
- 코루틴 사용이 많은 프로젝트: StateFlow
- 레거시 프로젝트 유지보수: LiveData
💡 실제 사례로 이해하기
게임 앱을 만든다고 생각해볼까요?
// LiveData 사용 - 간단한 점수 표시
class SimpleGameViewModel : ViewModel() {
private val _score = MutableLiveData(0)
val score: LiveData<Int> = _score
fun addScore() {
_score.value = (_score.value ?: 0) + 10 // 메인 스레드에서 실행
}
}
// StateFlow 사용 - 복잡한 게임 상태 관리
class AdvancedGameViewModel : ViewModel() {
private val _gameState = MutableStateFlow(GameState())
val gameState = _gameState.asStateFlow()
fun processGameAction(action: GameAction) {
viewModelScope.launch(Dispatchers.IO) {
// 복잡한 게임 로직 처리
val newState = calculateNewState(action)
_gameState.value = newState
}
}
}
🎯 핵심 포인트
- LiveData는 UI 업데이트에 최적화되어 있고, 안드로이드에 종속적
- StateFlow는 복잡한 데이터 처리에 강점
- LiveData는 안드로이드 생명주기에 특화된 관찰 가능한 데이터 홀더이고, StateFlow는 코루틴 기반의 반응형 스트림
- 둘 다 데이터 변경을 관찰하는 도구
- 프로젝트 상황에 맞게 선택하면 됨
글을 읽어주셔서 감사합니다.
참고문헌:
반응형