컴포즈에서 뷰모델을 생성 시 크게 두 가지 방법이 사용된다.
viewModel()를 이용한 생성과 hiltViewModel() 를 이용한 생성, 두가지 방법을 자세히 알아보자
NavBackStackEntry, ViewModelStoreOwner - NavBackStackEntry와 컴포즈에서의 ViewModel 공유
CompositionLocal → CompositionLocal 참고
먼저 viewModel() 함수를 살펴보자
@Suppress("MissingJvmstatic")
@Composable
public inline fun <reified VM : ViewModel> viewModel(
viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
"No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
},
key: String? = null,
factory: ViewModelProvider.Factory? = null,
extras: CreationExtras = if (viewModelStoreOwner is HasDefaultViewModelProviderFactory) {
viewModelStoreOwner.defaultViewModelCreationExtras
} else {
CreationExtras.Empty
}
): VM = viewModel(VM::class, viewModelStoreOwner, key, factory, extras)
가장 먼저 viewModelStoreOwner라는 변수에 LocalViewModelStoreOwner.current 로 현재 ViewModelStoreOwner 를 불러옴
일단 결과부터 말하자면 LocalViewModelStoreOwner.current는 현재 컴포즈 뷰에 대해서 최상위 뷰의 ViewModelStoreOwner를 불러온다.
public object LocalViewModelStoreOwner {
private val LocalViewModelStoreOwner =
compositionLocalOf<ViewModelStoreOwner?> { null }
/**
* Returns current composition local value for the owner or `null` if one has not
* been provided nor is one available via [findViewTreeViewModelStoreOwner] on the
* current [androidx.compose.ui.platform.LocalView].
*/
public val current: ViewModelStoreOwner?
@Composable
get() = LocalViewModelStoreOwner.current ?: findViewTreeViewModelStoreOwner()
/**
* Associates a [LocalViewModelStoreOwner] key to a value in a call to
* [CompositionLocalProvider].
*/
public infix fun provides(viewModelStoreOwner: ViewModelStoreOwner):
ProvidedValue<ViewModelStoreOwner?> {
return LocalViewModelStoreOwner.provides(viewModelStoreOwner)
}
}
ViewModelStoreOwner.current - ViewModelStoreOwner? 타입의 변수
LocalViewModelStoreOwner 라는 이름의 CompositionLocal 인스턴스에 대해, .current를 호출하여 현재 CompositionLocal 에 provide된 ViewModelStoreOwner를 가져옴
findViewTreeViewModelStoreOwner() 를 통해 LocalView에 제공된 ViewModelStoreOwner를 찾아 리턴한다
/**
* The CompositionLocal containing the current Compose [View].
*/
val LocalView = staticCompositionLocalOf<View> {
noLocalProvidedFor("LocalView")
}
@JvmName("get")
public fun View.findViewTreeViewModelStoreOwner(): ViewModelStoreOwner? {
return generateSequence(this) { view ->
view.parent as? View
}.mapNotNull { view ->
view.getTag(R.id.view_tree_view_model_store_owner) as? ViewModelStoreOwner
}.firstOrNull()
}