이번 포스팅에서는 Compose 예제들을 분석하고 입력해보며 알게된 부분들을 정리해보고자 한다.
그 중 Crane 프로젝트를 살펴보자.
이번 포스팅에서는 Compose와 함께 사용하고 있는 Navigation Component에 대해 한 번 살펴 볼 것이다.
먼저 Crane 프로젝트는 Navigation Coomponent를 사용하고 있다.
Navigation은 MainActivity의 onCreate() 에서 다음과 같이 사용되고 있다.
calculateWindowSizeClass()
액티비티에서 제공해준 화면의 크기를 구하는 함수다.때문에 파라미터로 Activity를 받는다.
WindowWidthSizeClass 뿐만 아니라, WindowHeightSizeClass로 높이와 너비 모두 구하는 것이 가능하다.
rememberNavController()
Stateful한 Navigation API인 NavController를 만드는 메서드이다.
선언한 NavController는 다양한 메서드로 프레그먼트를 관리한다.
navigate(설정한 Route)
NavHost 안에 설정한 Composable(설정한 Route)의 경로를 넣어서 이동한다.
getBackStackEntry(설정한 Route)
fragment 간의 데이터 전달이나 viewModel 공유 등을 위해 사용하고, 이 예시 같은 경우는 메인에서의 viewModel을 Calendar 화면에서도 공유하여 사용하기 위해 사용되었다.
NavBackStackEntry은 Navigation의 Back Stack 그 자체를 가리키는 것이 아니라 이름처럼 Back Stack의 entry 역할을 한다.
즉, NavBackStackEntry를 사용하여 현재 탐색 그래프의 범위를 가져오고 이를 ViewModelStoreOwner로 사용하여 해당 범위에 대한 뷰 모델을 가져올 수 있다.
popBackStack()
NavController.popBackStack()은 자바의 stack이 상단의 데이터를 pop하는 것 뿐만 아니라 그 값을 가지고 오듯, 백 스택에서 팝한 후 다른 대상이 최상단에 성공적으로 다시 배치되었는지를 나타내는 부울을 반환한다.
이 메서드가 false를 반환하는 가장 일반적인 경우는 그래프의 시작 대상을 수동으로 팝할 때이다.
이 메서드가 false를 반환하면 NavController.getCurrentDestination()은 null을 반환하고, 활동의 finish()를 호출하여 팝을 처리해야 한다.
if (!navController.popBackStack()) {
// Call finish() on your Activity
finish()
}
여기까지가 이 프로젝트에서 네비게이션을 사용하는 방법이고, 프로젝트를 진행하며 추가적으로 사용되는 메서드는 추후에 정리하도록 하자.
NavHost
네비게이션의 영역을 정의하고, 안에는 NavController, 첫 목적지 등을 정의한다.
composable()
NavHost 안에 각 목적지를 설정할 때에 사용된다. 이 안에 동반되는 viewModel과 화면에 대한 정의가 5번처럼 정의된다.
구현할 네비 목적지의 화면이다.
remember
이것은 네비게이션과는 무관하지만, Compose의 생명주기를 앞서 이해하고 넘어왔고, 뒤에 심심찮게 등장 할 것이기 때문에 미리 짚고 넘어가자는 의미로 넣게 되었다.
remember를 언제 사용해야 할까?
한 문장으로 설명하면 다시 하고 싶지 않은 비싼 작업을 수행해야 할 때 혹은 recomposition이 되어도 데이터를 보존해야 할 때 사용하는 것이 좋다.
예를 들어 텍스트 포매팅 같은 작업들 말이다. 전통적인 안드로이드 View 시스템에서 onDraw() 함수를 한 번씩 써본 사람들은 알겠지만 이 메서드는 매우 자주 호출이 돼서 Paint를 전역 변수로 저장해서 사용하라는 말을 들은 적이 있을 것이다. Composable 함수도 마찬가지로 recomposition이 매우 자주 실행될 수 있기 때문에 생성하는 데 오래 걸릴 만한 것들은 remember을 사용해서, 값을 recomposition을 할 때마다 새로 생성하지 않고 원래 있던 것을 쓰고 싶을 때 쓰면 된다.
상태를 저장하는 compose의 함수는 remember 말고도 하나 더 있다.
이 둘의 차이는 다음과 같다.
@Composable
fun MyComposable() {
var a by rememberSaveable { mutableStateOf(true) }
var b by remember { mutableStateOf(true) }
if (shouldShowOnboarding) {
OnboardingScreen(onFinish = {
a = false
})
} else {
ContentScreen(onFinish = {
b = false
})
}
}
기본적으로 저장한 a와 b는 값을 유지하는 데에 사용된다. 하지만 하위에서 차이가 있다.
rememberSaveable로 선언한 a는 하위에서 false로 변화가 일어나도 상위의 a는 그대로 true를 유지한다.즉 하위 composable에서 사용하기 위해 초기값 설정이 가능하다.
remember로 선언한 b는 하위에서 false로 변화가 일어나면 상위의 b도 false로 변화한다.
즉, remember/rememberSavable 둘 다 recomposition과 같은 compose 특성으로 인해 초기값을 설정하고 구성의 변화에 있어 이를 유지하기 위해 사용되지만,remember는 이후에 사용할 composable에서 초기값 설정이 불가능하고 rememberSaveable에서는 이후에 사용할 composable에서 초기값 설정이 가능하다는 점에서 차이가 있다.
다음 포스팅에서는 Navigation을 통해 이동되는 뷰들이 어떻게 구현됐는지 세부적으로 살펴보도록하자.
https://jaeyeong951.medium.com/navigation-component%EC%9D%98-%EA%B2%B0%EA%B3%BC%EA%B0%92-%EC%A0%84%EB%8B%AC%ED%95%98%EA%B8%B0-c10e795d6858
https://stackoverflow.com/questions/69642441/how-to-share-a-viewmodel-between-navgraph-components-only
https://developer.android.com/guide/navigation/navigation-navigate?hl=ko
https://blog.onebone.me/post/jetpack-compose-remember/