회사 선임분에게 감사의 인사를
최근에 Compose 에서 viewModel 을 파라미터로 넘겨서 사용할 때, 편의를 위해 compositionLocalOf 메서드를 사용하여 같은 Composable Scope 안에서는 currentViewModel() 과 같이 호출하여 당시에 제공하는 Composable Scope 에 맞는 ViewModelStoreOwner 를 넣어주고 viewModel 을 사용할 수 있도록 구성하여 사용하고 있습니다.
compositionLocalOf 를 사용할 때, Theme 등의 전파의 개념에만 사용하는 것을 구글 가이드에서는 추천하고 있기 때문에, Interface 형식(AAC 의 의존성도 제거할겸)으로 만들어 사용하고 있습니다.
별문제 없이 사용하다가, 특정 상황에서 currentViewModel 인스턴스가 새롭게 생기는 일이 발생하였습니다.
특정상황은 아래 이미지와 같이 Compose Navigation 을 사용할 때, composable 함수 안에서 인스턴스가 새롭게 생겼습니다.
(Compose 가 아닌 기존의 Jetpack Navigation component 를 사용할 때 Fragment 안에서 viewModel 를 선언해서 사용하면 해당 Fragment 에 대해서만 생기는 것과 같다고 생각하시면 됩니다. 따라서 우리는 경우에 따라서 activityViewModel 같은 것을 만들어서 사용해야 합니다)
알고보니, Compose NavHost 의 코드중 LocalOwnersProvider 라는 함수안에서 LocalViewModelStoreOwner 를 this 로 다시 제공하며 ViewModelStoreOwner 가 변경되어 새로운 인스턴스로 제공 되고 있었습니다.
이를 해결하기 위해서는 여러가지 방법이 있을 것 같은데, 우선은 currentViewModel() 로 사용할때 그때그때 Factory 로 Scope 에 맞는 viewModel 을 제공하는 것이 아닌, 한번만 만들어서 사용하는 식으로 변경하였습니다.
또는
val viewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) {
"No ViewModelStoreOwner was provided via LocalViewModelStoreOwner"
}
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "first") {
composable("first") {
// 이런식으로 viewModel 에 owner 를 직접 넣어줄 수도 있습니다.
val model = viewModel<SharedModel>(viewModelStoreOwner = viewModelStoreOwner)
}
composable("second") {
// 혹은 CompositionLocalProvider 를 사용하여 viewModelStoreOwner 를 제공해줄수도 있습니다.
CompositionLocalProvider(
LocalViewModelStoreOwner provides viewModelStoreOwner
) {
SecondScreen()
}
}
}
위와 같이 viewModel 에 직접 넣어줄 수도 있고, viewModelStoreOwner 를 CompositionLocalProvider 를 통해 전파시켜줄수도 있습니다.
그럼 20000 :)
'Android > Today I Learned' 카테고리의 다른 글
Material library 1.5.0 로 올리니 크래시가?! (1) | 2022.03.11 |
---|---|
Compose 버튼 사이즈 관련 Tips (1) | 2022.03.01 |
Android Font 고군분투기 (1) | 2021.12.06 |
Coil 로 OnDemand-image-resizing 적용하기 (0) | 2021.11.23 |
Glide cache 제거 하기 (0) | 2021.11.21 |