Jetpack Compose를 사용하여 Android 앱을 개발할 때, 여러 화면에서 데이터를 공유해야 하는 경우가 많습니다. 특히, ViewModel을 사용하여 UI 상태를 관리할 때, 화면 간에 ViewModel 인스턴스를 어떻게 공유할지가 중요한 문제가 됩니다. 이 글에서는 Jetpack Compose Navigation에서 NavBackStackEntry를 활용하여 ViewModel을 공유하는 가장 효과적이고 권장되는 방법을 자세히 설명하겠습니다.
ViewModel은 UI 관련 데이터를 저장하고 관리하는 데 사용되는 아키텍처 구성 요소입니다. ViewModel을 사용하면 UI 로직과 데이터 로직을 분리하여 코드를 더 깔끔하고 유지 보수하기 쉽게 만들 수 있습니다.
하지만, 앱이 여러 화면으로 구성되어 있을 때, 각 화면마다 독립적인 ViewModel 인스턴스를 생성하면 데이터 공유가 어려워집니다. 예를 들어, 타이머 앱에서 타이머 설정 화면과 타이머 실행 화면이 있다고 가정해 보겠습니다. 타이머 설정 화면에서 설정한 시간을 타이머 실행 화면에서 사용하려면, 두 화면이 동일한 ViewModel 인스턴스를 공유해야 합니다.
Jetpack Compose Navigation에서 ViewModel을 공유하는 방법은 여러 가지가 있지만, 그중에서도 NavBackStackEntry를 활용하는 방법이 가장 권장됩니다. 이 방법은 다음과 같은 장점을 제공합니다.
NavBackStackEntry는 Jetpack Compose Navigation에서 탐색 스택의 항목을 나타내는 객체입니다. 각 화면으로 이동할 때마다, 해당 화면에 대한 NavBackStackEntry가 탐색 스택에 추가됩니다. NavBackStackEntry는 다음과 같은 정보를 제공합니다.
NavBackStackEntry를 활용한 ViewModel 공유의 핵심은 NavGraph의 ViewModelStoreOwner를 이용하는 것입니다.
다음은 NavBackStackEntry를 활용하여 ViewModel을 공유하는 구체적인 방법입니다.
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Screen.TimerScreen.route) {
composable(Screen.TimerScreen.route) { entry ->
val parentEntry = remember(entry) {
navController.getBackStackEntry(Screen.TimerScreen.route)
}
val timerViewModel: TimerViewModel = hiltViewModel(parentEntry)
...
}
composable(Screen.OneMinuteScreen.route) { entry ->
val parentEntry = remember(entry) {
navController.getBackStackEntry(Screen.TimerScreen.route)
}
val timerViewModel: TimerViewModel = hiltViewModel(parentEntry)
...
}
composable("Screen.MoreScreen.route) { entry ->
val parentEntry = remember(entry) {
navController.getBackStackEntry(Screen.TimerScreen.route)
}
val timerViewModel: TimerViewModel = hiltViewModel(parentEntry)
...
}
}
}