Android/학습

[Android] ViewModel Instance 생성 with ViewModelProvider

한때미 2024. 11. 28. 19:56

 

ViewModel은 생성될 때 전달받은 ViewModelStoreOwner 생애주기를 따라간다.

 

https://androidhelper.tistory.com/23

 

[Android] Jetpack ViewModel

ViewModel비즈니스 로직 또는 화면 수준 상태 홀더로,UI 컨트롤러의 데이터를 캡슐화하여 구성 변경이 일어나도 데이터를 유지하는 것이 목적인 구성요소이다. 즉, UI에 상태를 노출하고 관련 비즈

androidhelper.tistory.com

 

그렇다면 ViewModelStoreOwner 생애주기를 따르는 ViewModel의 생성하려면,

즉, ViewModel의 인스턴스는 어떻게 해야 올바르게 생성해서 사용할 수 있을까?

 


ViewModelProvider를 사용하는 방법

 

ViewModelProvider를 사용하여 viewModel 인스턴스를 만들려면 다음과 같이 사용할 수 있다.

viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

 

 

ViewModelProvider를 이용하여 ViewModel 인스턴스를 생성할 때 this

즉, Activity(ViewModelStoreOwner)를 전달하였다.

 

(이 경우에는 Activity에서 this를 호출하였을 경우이다)

class MainActivity : AppCompatActivity() {
 
    private lateinit var viewModel: MyViewModel
 
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
 
        viewModel = ViewModelProvider(this).get(MyViewModel::class.java)
    }
}

 

 

ViewModelProvider 통해서 ViewModel의 인스턴스를 가져온 것이다.

 

 

그렇다면 viewModelProvider은 어떻게 ViewModel의 인스턴스를 생성하는 것일까?

 


ViewModelProvider

 

ViewModelProvider는 다음과 같은 클래스 이다.

public actual open class ViewModelProvider private constructor(
    private val impl: ViewModelProviderImpl,
)

 

앞에서 우리는 ViewModel 인스턴스를 생성하기 위하여

ViewModelProvider의 생성자를 호출하였는데,

 

우리가 호출한 ViewModelProvider의 생성자는 다음과 같다.

ViewModelProvider의 생성자 중 하나, owner만 전달된 경우

 

여기서 알 수 있듯이, 특별한 경우가 아닌 경우 DefaultFactory를 제공해주는 것을 확인할 수 있다.

Factory를 통해 ViewModel의 새로운 인스턴스 생성과 관리를 하는 것이다.

 

 

 

ViewModel을 생성하는 Factory에 대해서

좀 더 자세히 알아보자.

 

 

우선 factory 객체는 ViewModelProviders에서 메서드를 호출해서 생성하는 것을 확인할 수 있다.

internal object ViewModelProviders

해당 ViewModelProviders object(Singleton)에는 다음과 같은 메서드가 존재한다.

internal fun getDefaultFactory(owner: ViewModelStoreOwner): ViewModelProvider.Factory =
        if (owner is HasDefaultViewModelProviderFactory) {
            owner.defaultViewModelProviderFactory
        } else {
            DefaultViewModelProviderFactory
        }

 

여기서 owner가 HasDefaultViewModelProviderFactory일 경우

owner.defaultViewModelProviderFactory를 Facotry로 사용하는 것을 알 수 있다.

 

 

그럼 HasDefaultViewModelProviderFactory는 무엇인가?

여기서 ComponentActivity, Fragment를 다시 살펴보면 다음과 같다.

 

ViewModelStoreOwner를 상속받는 ComponentActivity가 HasDefaultViewModelProviderFactory를 상속하는 모습
ViewModelStoreOwner를 상속받는 Fragment가 HasDefaultViewModelProviderFactory를 상속하는 모습

 

 

결국 일반적으로 Activity, Fragment (+ NavBackStackEntry)에 의존하는 ViewMoel을 생성할 때

ViewModel를 생성하는 DefaultFactory는 

 

owner의 defaultViewModelProviderFactory를 호출하는 것이다.

그리고 여기서 owner라고 한다면 ComponentActivity, Fragment (+ NavBackStackEntry)가 될 것이고

 

owner의 defaultViewModelProviderFactory는 다음과 같다.

 

defaultViewModelProviderFactory

ComponentActivity의 defaultViewModelProviderFactory
Fragment의 defaultViewModelProviderFactory

 

 

음! 결국 돌고 돌아 ViewModel의 인스턴스를 생성하는 DefaultFactory는

일반적으로 SavedStateViewModelFactory가 되는 것이다.

 


SavedStateViewModelFactory

ViewModel의 인스턴스를 생성하는 Factory,

SavedStateViewModelFactory는 다음과 같은 class이다.

 

SavedStateViewModelFactory class


잠시 앞에 나왔던 내용을 다시 되새기면,

 

우리는 ViewModel 인스턴스가 어떻게 만들어지는지 알아보던 중

Factory를 통해 ViewModel 인스턴스가 생긴다는 것을 알게 되고,

 

DefaultFactory가 ViewModelProvider.Factory로 생성된다는 것을 알게 되었으며,

 

ViewModelProvider에서 Factory, ViewModelProvider.Factory가 무엇인지 알아보고 있는 중이다.

일반적으로 ViewModelProvider에서 getDefaultFactory로 SavedStateViewModelFactory 객체를 불러오는 것을 확인하였다.

그러던 중 SavedStateViewModelFactory라는 구체적인 구현체도 알게 된 것 이다.

 

🌈 factory의 정체 == SavedStateViewModelFactory

 

ViewModelProvider의 생성자 중 하나, owner만 전달된 경우
ViewModelProviders object의 getDefaultFactory

 

 

다시 SavedStateViewModelFactory class를 살펴보면 다음과 같다.

SavedStateViewModelFactory

@SuppressLint("LambdaLast")
    constructor(application: Application?, owner: SavedStateRegistryOwner, defaultArgs: Bundle?) {
        savedStateRegistry = owner.savedStateRegistry
        lifecycle = owner.lifecycle
        this.defaultArgs = defaultArgs
        this.application = application
        factory = if (application != null) getInstance(application)
            else ViewModelProvider.AndroidViewModelFactory()
    }

 

 

Factory는 다음과 같은 코드로 생성된다.

AndroidViewModelFactory(application)
ViewModelProvider.AndroidViewModelFactory()

 

JvmViewModelProviders

실제로 ViewModel의 생성은 JvmViewModelProviders에서 담당하는 것을 확인할 수 있다.

 

JvmViewModelProviders에서 호출되는 것을 확인

 


 

참고로 처음에 ViewModel 인스턴스를 가져온 코드에서

viewModel = ViewModelProvider(this).get(MyViewModel::class.java)

 

ViewModelProvider에서 호출되는 get()을 따라가면 해당 함수를 확인할 수 있다.

 

ViewModelProviderImpl

 

해당 로직에서 확인할 수 있는데,

 

ViewModel을 생성하려고 할 때 인스턴스가 있는지 확인하고

인스턴스가 존재하는 경우 해당 ViewModel을 넘겨주는 것을 확인할 수 있다.

 

 

ViewModelProvider와 연관된 범위(일반적으로 fragment이나 Activity)에서 기존 ViewModel을 반환하거나 새 ViewModel을 생성한다.

 


To Be Continued

  • 생성자가 있는 viewModel 생성
  • JvmViewModelProviders
  • by viewModels(), ktx
  • by lazy, 위임 패턴

참고자료

https://developer.android.com/reference/androidx/lifecycle/ViewModelProvider

 

ViewModelProvider  |  Android Developers

androidx.appsearch.builtintypes.properties

developer.android.com