본문 바로가기
안드로이드 공부 노트/Compose(컴포즈)

[Android-Compose] 컴포즈 NavHost에서 ViewModel 공유 예제를 통해 알아보기 - Screen끼리 공유

by 지게요 2024. 12. 7.
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 값 공유가 가능하다!

 

반응형