728x90
반응형
이번 포스팅은 Compose에서 NavHost 사용 시 다른 Screen끼리 ViewModel을 공유해야 할 상황이 생긴다.
이때 ViewModel을 공유하는 방법을 포스팅해보겠다.
해결법을 바로 보고 싶으신 분은 결론으로 넘어가면 된다!
# 예제
이번 예제는 ScreenA와 ScreenB가 있고 같은 ViewModel를 사용해 데이터를 공유하는 상황이다.
또한 DI 라이브러리를 사용 안 하는 상황
프로세스를 자세히 표현하자면 아래와 같다.

## Before 코드
### MainActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
SideTheme {
NavHost(
modifier = Modifier.fillMaxSize(),
navController = navController,
startDestination = "ScreenA",
) {
composable(route = "ScreenA") {
ScreenA(navController)
}
composable(route = "ScreenB") {
ScreenB()
}
}
}
}
}
}
### MainViewModel
class MainViewModel : ViewModel() {
var name by mutableStateOf("")
private set
fun updateName(name: String) {
this.name = name
}
}
### ScreenA
@Composable
fun ScreenA(
navController: NavHostController,
viewModel: MainViewModel = viewModel()
) {
LaunchedEffect(key1 = Unit) {
viewModel.updateName("지게")
}
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "ScreenA ${viewModel.name}"
)
Button(
onClick = {
navController.navigate("ScreenB")
},
modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
){
Text(text = "ScreenB 이동")
}
}
}
### ScreenB
@Composable
fun ScreenB(
viewModel: MainViewModel = viewModel()
) {
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(
text = "ScreenB ${viewModel.name}"
)
}
}
코드에서 보다시피 MainViewModel에 있는 name 값을 ScreenA, ScreenB 둘 다 공유하려고 한다.
하지만 위 코드들을 실행시켜 보면 ScreenB에는 viewModel.name 이 나오지 않는 걸 알 수 있다.

## After 코드
### MainActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
SideTheme {
NavHost(
modifier = Modifier.fillMaxSize(),
navController = navController,
startDestination = "ScreenA",
) {
composable(route = "ScreenA") {
ScreenA(navController)
}
composable(route = "ScreenB") {
// navController.getBackStackEntry 사용
val viewModel = viewModel<MainViewModel>(
// route에는 공유 받고 싶은 Screen Route를 적어준다.
navController.getBackStackEntry("ScreenA")
)
ScreenB(
viewModel = viewModel
)
}
}
}
}
}
}

기존코드와 바뀐 코드는 MainActivity만 바뀌었다.
코드를 보면 Navigation Graph세팅 시 navController.getBackStackEntry을 활용해 ViewModel을 만들고 있다.
# 결론
navController.getBackStackEntry을 활용하면 다른 Screen이어도 viewmodel 값 공유가 가능하다!
반응형