안드로이드

LifeCycle Of ViewModel

pjm1n 2025. 10. 5. 22:33

❓ViewModel의 생명주기는 왜 중요할까

안드로이드 UI 컴포넌트는 생명주기에 따라 생성되고 파괴된다. 예를 들어 다크모드, 프로세스 강제 종료 후 복원, 화면 회전 같은 configuration change가 일어났을 때 생성→파괴→생성이 반복된다. 따라서 fragmentactivity 내부의 데이터는 모두 초기화된다.

ViewModelactivityfragment의 생명주기보다 한 단계 더 길게 유지된다. 따라서 해당 데이터를 유지하기 위해서는 ViewModel을 사용한다.

🔁 ViewModel의 생명주기

configuration change 대응

ViewModelactivityFragment에 인스턴스화했음에도 생명주기가 더 길까? 그 이유는 ViewModelStore에 있다. activity가 상속 받는 ComponentActivity는 내부적으로 다음과 같은 구조를 갖는다.

class ComponentActivity : ViewModelStoreOwner {

    private var mViewModelStore: ViewModelStore? = null



    override fun getViewModelStore(): ViewModelStore {

        if (mViewModelStore == null) {

            mViewModelStore = ViewModelStore()

        }

        return mViewModelStore!!

    }

}

activity 안에 ViewModelStore라는 공간이 따로 존재마고, 모든 ViewModel은 여기에 저장된다.

화면회전 같은 configuration change가 발생하면 안드로이드가 새로운 activity를 만들어주지만, 그 전에 시스템이 이건 단순 재생성이라는 것을 알고 기존 ViewModelStore를 재사용한다. 즉, 기존에 생성되었던 ViewModel의 인스턴스를 그대로 사용한다.

파괴 시점

사용자가 뒤로가기로 나가거나 시스템이 프로세스를 죽이면 이제는 이 activity는 필요 없게 되므로 ViewModel도 같이 파괴해주어야한다. 그 때 안드로이드 프레임워크가 ViewModelStore.clear()를 호출해서 ViewModelonCleared()를 실행하고 정리한다.

  • activityfinish 될 때
  • fragmentdetach될 때
  • Navigation Entryback stack에서 제거 될 때

🙋‍♂️ViewModel 선언(생성)

1. by viewModels()

class MainActivity : AppCompatActivity() {

    private val viewModel: MainViewModel by viewModels<MainViewModel>()



    ...

}

접근 시점에 ViewModellazy하게 초기화된다. 내부 구현은 아래 코드와 같다.(Activity)

@MainThread

public inline fun <reified VM : ViewModel> ComponentActivity.viewModels(

    noinline extrasProducer: (() -> CreationExtras)? = null,

    noinline factoryProducer: (() -> ViewModelProvider.Factory)? = null

): Lazy<VM> {

    val factoryPromise = factoryProducer ?: { defaultViewModelProviderFactory }



    return ViewModelLazy(

        VM::class,

        { viewModelStore },

        factoryPromise,

        { extrasProducer?.invoke() ?: this.defaultViewModelCreationExtras }

    )

}
  • extrasProducerviewModel을 생성할 때 SavedStateHandle과 같은 추가적인 컨텍스트 정보를 전달한다. 기본적으로는 defaultViewModelCreationExtras를 사용한다.
  • factoryProducerViewModel의 생성을 어떻게 할지 커스텀할 수 있다. 즉,ViewModelProvider.Factory를 어떻게 얻을지 결정한다.
  • noinline 키워드가 붙은 이유는 viewModels()inline함수이므로 호출 시점에 코드가 그대로 복사되어 들어간다. 하지만 extrasProducerfactoryProducer는 이 람다를 인라인시키면 런타임에 저장할 수 없기 때문에 noinline키워드를 붙여주어야한다.

여기서 thisComponentActivity 자신이기 때문에 ViewModelStore를 가지고 있으므로 위에 언급한 내용과 같이 ViewModel의 인스턴스를 저장하고, activity가 파괴되면 ViewModel 또한 파괴시킨다.

2. 직접 생성

class MainActivity : AppCompatActivity() {

    private val viewModel by lazy {

        ViewModelProvider(this)[MainViewModel::class.java]

    }

}

1번 코드와 2번 코드의 차이점은 거의 없지만, SavedStateHandle의 자동 주입 차이가 있다.

SavedStateHandle은 프로세스 종료 같은 상황에 ViewModel에서 UI 상태를 안전하게 저장하고 복원할 수 있도록 만들어진 객체이다. 기본적으로 key-value 형태로 데이터를 저장하고, 뷰모델이 생성되었을 때 기존의 저장된 값이 있는 SavedStateHandle를 주입한다.

class MyViewModel(private val state: SavedStateHandle) : ViewModel()

다음과 같은 ViewModel이 있다고 가정했을 때, 1번 코드와 같이 위임 방식을 사용하면 viewModels()defaultViewModelProviderFactory프로퍼티의 SavedStateViewModelFactorySavedStateHandle을 생성해서 주입할 수 있도록 해주기 때문에SavedStateHandle의 생성자 주입이 자동으로 된다. 하지만 2번 코드는 직접 수동으로 주입해주어야한다.

🙌 결론

  1. ViewModelStoreOwnerViewModelStore를 통해 해당 컴포넌트와 ViewModel의 생명주기를 맞추거나 configuration Change에 대응할 수 있다.
  2. SavedStateHandle을 통해 프로세스가 종료되고 viewModel이 파괴되어도 데이터를 복원하여 configuration Change에 대응할 수 있다.