-
Notifications
You must be signed in to change notification settings - Fork 0
⚙ [기술 분석] ViewModel 공유
검색 기능을 구현할 때, paging으로 받아온 게시물을 누르고, Vertical Pager로 구현된 Detail Screen으로 이동했을 때, 다시 Paging3 라이브러리를 사용해서 게시물을 받아온다면, 불필요한 로딩 시간으로 인해 사용자들이 불편함을 느낄 것이다. 이를 위해 두 개의 screen에서 Paging Data를 재사용할 수 있도록 ViewModel을 공유하고자 했다.
뷰모델을 공유하기 위해 먼저 NavBackStackEntry의 역할을 알아야한다. NavBackStackEntry는 현재 네비게이션 스택에서 특정 목적지의 상태를 나타낸다. NavBackStackEntry에는 화면 자체의 정보(destination), 전달 데이터(arguments), 생명주기(lifecycle), 상태 저장/복원(savedState) ,화면과 관련된 뷰모델(viewModel) 를 포함한다.
즉, NavBackStackEntry는 해당 라우트의 생명 주기를 관리하는 역할을 한다.
Porring에서는 HiltViewModel을 사용하고 있다. hiltViewModel의 내부 코드를 보면 viewModelStoreOwner을 필요로 하고 있는 것을 볼 수 있다. ViewModel은 ViewModelStoreOwner의 생명주기를 따른다. 예를 들어, activity가 소멸되면 해당 acivity에 연결된 viewmodel도 소멸된다.
@Composable
public inline fun <reified VM : ViewModel> hiltViewModel(
viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner. current) { "No ViewModelStoreOwner was provided via LocalViewModelStoreOwner" },
key: String? = null
): VM
Jetpack Compose에서 NavBackStackEntry를 사용하면, 해당 목적지에 연결된 ViewModel을 생성할 수 있다. NavBackEntry가 ViewModelStoreOwner의 역할을 수행한다고 볼 수 있는데, 이렇게 한다면, 해당 목적지(화면)가 활성화되어 있는 동안에만 ViewModel이 유지된다.
navBackStackEntry = { navigator.navController.getBackStackEntry(MainMenu.Home.route) }
fun NavGraphBuilder.searchNavGraph(
padding: PaddingValues,
navigateToTheir: (String) -> Unit,
navigateToSearchDetail: () -> Unit,
popBackStack: () -> Unit,
getBackStackEntry: () -> NavBackStackEntry
) {
composable<MainMenuRoute.Search> { backStackEntry ->
val parentEntry = remember(backStackEntry) {
getBackStackEntry()
}
SearchRoute(
padding = padding,
viewModel = hiltViewModel(parentEntry),
navigateToSearchDetail = navigateToSearchDetail
)
}
composable<Route.DetailSearch> { backStackEntry ->
val parentEntry = remember(backStackEntry) {
getBackStackEntry()
}
DetailSearchRoute(
padding = padding,
viewModel = hiltViewModel(parentEntry),
navigateToTheir = navigateToTheir,
popBackStack = popBackStack
)
}
}
위의 코드를 보면, getBackStackEntry 메서드를 통해 “Home” 라우트에 대한 NavBackStackEntry를 가져온다.
hiltViewModel(parentEntry)를 사용하며 searchViewmodel을 생성할 때, 이 ViewModel은 parentEntry의 생명주기에 따라 관리된다. 즉, “Home" 라우트가 활성화되어 있는 동안에만 ViewModel이 생성되고, "Home" 라우트가 사라지면 ViewModel도 소멸된다.
두 개의 composable에서 각각 hiltviewmodel을 호출하면, 동일한 NavBackStackEntry를 참조하므로 동일한 ParentViewModel 인스턴스를 가져온다. 이로 인해 SearchRoute와 DetailSearchRoute가 동일한 Viewmodel 상태를 공유하게 된다. 실제로 두 screen이 같은 뷰모델을 공유하는지 확인해본 결과, 아래 로그 사진과 같이 정상적으로 동일 인스턴스를 공유하는 것을 확인했다.
Copyright 2024. Team Kolown All Rights Reserved.
- ✅ [기술 결정] Camera
- ✅ [기술 결정] Image Load
- ✅ [기술 결정] UI Toolkit - Copmpose
- ✅ [기술 결정] 데이터 별 UID 생성
- ✅ [기술 결정] Debounce & Paging 사용해서 검색 구현
- ✅ [기술 결정] Google Login
- ✅ [기술 결정] 스켈레톤 UI
- ⚙ [기술 분석] DI
- ⚙ [기술 분석] Image Compress
- ⚙ [기술 분석] 이미지 리사이징
- ⚙ [기술 분석] CameraX API
- ⚙ [기술 분석] Firebase & 랜덤 로딩
- ⚙ [기술 분석] ViewModel 공유
- ⚙ [기술 분석] Firestore 쿼리 전략
- ⚙ [트러블 슈팅] Chip with TextField(Custom with IntrinsicSize)
- ⚙ [트러블 슈팅] WindowInset
- ⚙ [트러블 슈팅] UI 실시간 반영
- ⚙ [트러블 슈팅] IME Padding
- ⚙ [트러블 슈팅] PagingSource reset
- ⚙ [트러블 슈팅] SharedFlow - SnackBar
- ⚙ [트러블 슈팅] Camera와 Lifecycle 동기화