안드로이드 프레임워크·시스템 학습 노트 목차

ViewModel·LiveData·StateFlow — 화면 상태를 살린다

ViewModel은 안드로이드에서 화면 상태와 그 로직을 담는 자리다 — 화면(Activity/Fragment)보다 오래 살아 회전에도 상태를 지킨다. 그 상태를 화면에 흘리는 관찰 가능한 홀더LiveData(고전)와 StateFlow(현대)다. 이 장은 안드로이드 위에서 ViewModel·관찰·생명주기 안전 수집을 묶는다. (출처: Android — ViewModel / StateFlow & LiveData.)

ViewModel — 화면보다 오래 사는 상태 홀더

ViewModel은 구성 변경(회전)에도 유지되고, 화면이 완전히 끝날 때(onCleared)에만 소멸한다. 그래서 네트워크로 받은 목록·입력 중인 폼 같은 화면 상태를 여기 두면 회전에 날아가지 않는다.

class MemberViewModel(private val repo: MemberRepository) : ViewModel() {
    private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
    val uiState: StateFlow<UiState> = _uiState.asStateFlow()

    init { refresh() }
    fun refresh() = viewModelScope.launch {              // ViewModel 소멸 시 자동 취소
        _uiState.value = runCatching { repo.load() }
            .fold({ UiState.Success(it) }, { UiState.Error(it.message ?: "") })
    }
    override fun onCleared() { /* 자원 해제 */ }
}

viewModelScopeViewModel 전용 코루틴 스코프소멸 시 진행 중이던 코루틴을 자동 취소한다([andkt 07]) — 누수 없는 비동기의 핵심.

ViewModel을 얻는 법

// Compose
val vm: MemberViewModel = viewModel()              // 또는 hiltViewModel()
// Fragment/Activity KTX
private val vm: MemberViewModel by viewModels()

생성자에 의존성이 있으면 팩터리Hilt(@HiltViewModel)([andarch 05])로 주입한다. *같은 ViewModelStoreOwner(화면)*면 같은 인스턴스를 돌려받아 Fragment끼리 공유도 된다(activityViewModels).

LiveData vs StateFlow

둘 다 관찰 가능한 상태 홀더지만:

LiveDataStateFlow
출신안드로이드 전용코틀린(Flow)
초기값선택필수
생명주기 인지내장(observe)별도(repeatOnLifecycle/collectAsStateWithLifecycle)
연산자적음Flow 연산자 풍부
권장레거시신규 권장

구글은 신규 코드에 StateFlow(+ 생명주기 안전 수집)를 권장한다. 순수 코틀린이라 테스트·멀티플랫폼에 유리하고 Flow 생태계와 맞물린다.

생명주기 안전 수집 — 핵심 함정

StateFlow를 그냥 collect하면 백그라운드에서도 수집낭비·크래시가 난다. 화면이 보일 때만(STARTED) 수집하고 안 보이면 멈춰야 한다.

// Compose — 가장 간단 (권장)
val state by viewModel.uiState.collectAsStateWithLifecycle()

// View 시스템 — repeatOnLifecycle
viewLifecycleOwner.lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { render(it) }     // STARTED~STOPPED 구간만 수집
    }
}
다이어그램 로딩 중…

collectAsStateWithLifecycle()(Compose)와 repeatOnLifecycle(STARTED)(View)가 그 안전장치다 — 예전 LiveData.observe가 공짜로 주던 생명주기 인지를 StateFlow에선 이걸로 챙긴다.

정리 — 상태는 ViewModel에, 수집은 생명주기 안전하게

핵심 — ViewModel이 화면 상태를 보유(회전 생존·viewModelScope로 누수 없는 비동기), 상태는 StateFlow로 노출(신규 권장), 수집은 collectAsStateWithLifecycle/repeatOnLifecycle(STARTED)로 생명주기 안전하게. *상태를 올바른 자리(ViewModel)*에 두고 *올바른 방식(생명주기 안전)*으로 흘리는 것이 안드로이드 UI의 토대다.

한 줄 요약 — ViewModel=회전 생존 상태 홀더(viewModelScope 자동 취소·by viewModels()/hiltViewModel()). 상태 노출은 StateFlow(초기값 필수·신규 권장) vs LiveData(레거시·내장 생명주기). 수집은 *collectAsStateWithLifecycle(Compose)·repeatOnLifecycle(STARTED)(View)*로 안전하게.

(출처: Android — ViewModel / StateFlow / Lifecycle-aware collection / collectAsStateWithLifecycle.)

Compose 상태·side-effect — remember·LaunchedEffectRoom — 로컬 DB·DAO·관계·마이그레이션