[mvvm] 뷰모델 지피티 물음 정리3

말랑돌·2025년 8월 13일

안드로이드 학습

목록 보기
15/17

그럼 뷰 모델의 생명주기는 어떻게 되는거야?

Jetpack Compose에서 ViewModel의 생명주기는 ViewModelStoreOwner에 의해 결정됩니다.
즉, ViewModel 자체가 화면이 아니라 소유자(owner) 에 묶여서 살아있다가, owner가 사라질 때 같이 파괴됩니다.


1. ViewModel의 생명주기 기본 원리

  • ViewModel은 화면의 생명주기(Lifecycle) 와는 조금 다릅니다.

  • 실제로는 ViewModelStoreOwner(예: Activity, NavBackStackEntry)에 묶여서 유지됩니다.

  • 일반적인 경우:

    • Activity에 묶으면 → Activity가 파괴될 때까지 ViewModel이 유지됩니다.
    • NavBackStackEntry에 묶으면 → 해당 화면이 Navigation back stack에서 제거될 때 ViewModel이 파괴됩니다.

2. 예시로 보는 차이

// Activity 범위 ViewModel
val vm = viewModel<MainViewModel>()
// → Activity가 살아있는 동안 계속 유지됨.
// → 다른 화면 전환 후에도 같은 인스턴스 사용 가능.

// Navigation backStackEntry 범위 ViewModel
val vm = viewModel<MainViewModel>(backStackEntry = navBackStackEntry)
// → 이 backStackEntry가 pop될 때 ViewModel이 파괴됨.
// → 화면 전환 시 다른 인스턴스로 교체 가능.

3. backStackEntry를 사용하는 이유

  • Compose Navigation에서는 각 화면이 NavBackStackEntry라는 owner를 가짐.
  • viewModel(backStackEntry)로 지정하면
    → 화면 전환 시에도 backStackEntry가 남아 있는 한 ViewModel 상태를 유지.
  • 뒤로 가기(pop)로 backStackEntry가 제거되면
    ViewModel.onCleared() 호출 후 메모리에서 제거됨.

4. AppNavHost에서 ViewModel이 안 보이는데 동작하는 이유

  • Compose Navigation의 composable(route) { backStackEntry -> ... } 구문에서
    backStackEntry가 곧 ViewModelStoreOwner 역할을 합니다.
  • viewModel() 함수는 현재 Composition의 LocalViewModelStoreOwner를 자동으로 가져와 사용합니다.
  • 즉, factory나 owner를 명시하지 않아도 현재 화면의 backStackEntry에 자동 연결됩니다.

5. ViewModel 생명주기 요약

ViewModel 범위소유자(ViewModelStoreOwner)파괴 시점
Activity 범위ActivityActivity 종료 시
Navigation 범위NavBackStackEntrybackStackEntry pop 시
Fragment 범위FragmentFragment 종료 시

📌 핵심

  • ViewModel의 수명은 UI 컴포넌트의 생명주기가 아니라 ViewModelStoreOwner에 의해 관리됩니다.
  • Navigation을 쓰면 화면마다 독립된 생명주기를 가질 수 있어서, 같은 Activity 내에서도 화면별 ViewModel 유지/삭제가 가능합니다.

그러니까, 같은 viewmodel 클래스를 이용해서 인스턴스를 만들더라도, ViewModelStoreOwner에 따라서 별도의 viewmodel 인스턴스가 만들어지고, 저장되는 데이터도 서로 달라질 수 있는거야?

네, 정확하게 이해하셨습니다.

같은 ViewModel 클래스라도 ViewModelStoreOwner가 다르면
서로 완전히 독립된 ViewModel 인스턴스가 만들어지고, 각 인스턴스는 서로 다른 상태 데이터를 가집니다.


1. 왜 그런가?

  • ViewModel클래스 이름으로 인스턴스를 공유하는 게 아니라
    (ViewModelStoreOwner + ViewModel 클래스) 조합으로 고유하게 관리됩니다.
  • 내부적으로 ViewModelStoreOwnerViewModelStore라는 저장소를 갖고 있고,
    여기에 ViewModel 인스턴스를 Map 형태로 보관합니다.
  • owner가 다르면, 저장소 자체가 다르기 때문에 같은 클래스라도 다른 인스턴스가 생성됩니다.

2. 예시 코드

// Activity 범위 ViewModel
val vm1 = viewModel<MyViewModel>() // owner = Activity

// Navigation 범위 ViewModel (다른 화면 backStackEntry)
val vm2 = viewModel<MyViewModel>(owner = backStackEntryA)
val vm3 = viewModel<MyViewModel>(owner = backStackEntryB)
  • vm1, vm2, vm3는 모두 MyViewModel 클래스지만 완전히 다른 인스턴스입니다.
  • 당연히 vm2vm3state 데이터는 서로 전혀 공유되지 않습니다.

3. 실제 사용 시 장점

  • 화면별 상태 분리
    → 예: 로그인 화면 ViewModel, 회원가입 화면 ViewModel이 같은 클래스여도 독립적으로 데이터 유지 가능.
  • 다중 인스턴스 허용
    → 같은 화면을 여러 번 띄워도(backStack에 여러 개 쌓여도) 각 화면의 ViewModel 상태가 따로 유지.

4. 핵심 요약

  • 같은 ViewModel 클래스라도 ViewModelStoreOwner가 다르면 다른 저장소에 저장 → 다른 인스턴스 생성.
  • 저장된 데이터(LiveData, State, MutableStateFlow 등)도 각 인스턴스별로 독립.
  • ViewModel 공유 여부는 ViewModelStoreOwner를 누구로 지정하느냐에 달려 있음.

0개의 댓글