Jetpack Navigation 과 Back Stack

KiManSu
9 min readOct 27, 2022

--

동아리 프로젝트를 진행하던 도중 백스택 관리와 관련해서 애먹은 적이 있는데 그때의 기억을 되짚고자 네비게이션을 통한 백스택 관리에 대한 포스팅을 해보고자 합니다.

아찔했던 기억

이 그래프는 로그인와 회원가입 그리고 비밀번호 재설정에 관한 그래프 입니다.

  • 회원가입시 비밀번호 설정에서 뒤로가면 인증번호 확인이 아닌 이메일 인증 화면으로 돌아가고 싶었습니다.
  • 가입이 완료되면 회원가입에 관한 스택을 비우고 로그인 화면을 넘어가고 싶었습니다.
  • 비밀번호 재설정시 비밀번호 재설정 화면에서 뒤로가면 인증번호 확인이 아닌 이메일 인증 화면으로 돌아가고 싶었습니다.
  • 비밀번호 재설정이 완료되면 재설정에 관한 스택을 비우고 로그인 화면으로 넘어가고 싶었습니다.

지금 보면 그렇게 어려운 처리는 아니었습니다. 하지만 그 당시에는 popUpTo, popUpToInclusive 등 관련 옵션이나 함수들을 잘 몰랐기에 어려워했던 기억이 납니다.😥

그럼 자주 사용되는 popUpTo,popUpToInclusive 을 위의 상황에 도입해보고 다른 함수나 옵션이 있는지 확인해 봅시다.

Navigation과 back stack

먼저 가볍게 공식문서부터 살펴봅시다!

Jetpack Navigation에서는 navigate()가 호출될 때마다 스택의 최상단으로 해당 destination을 올립니다. 해당 스택을 위로 올릴 땐 navigateUp(), 뒤로갈때는 popBackStack()이 호출됩니다.

다이얼로그의 경우 FloatingWindow 인터페이스를 Implement하는데 이는 백 스택의 다른 목적지 위에 올라갑니다. 따라서 하나 이상의 FloatingWindow는 백 스택의 맨 위에만 존재할 수 있습니다. FloatingWindow가 없는 목적지로 갈 경우 자동으로 모든 FloatingWindow는 스택 최상단에서 pop 됩니다.

Dialog는 백스택의 최상단에만 존재

만약 유저가 위 백스택에서 다른 다이얼로그로 navigate 한다면 백스택 최상단에 추가됩니다.

다이얼로그 위로 다이얼로그가 쌓임

이 상황에서 만약 non-floating한 destination으로 navigate한다면 모든 FloatingWindow들은 백스택 최상단에서 pop되고 non-floating한 destination이 최상단으로 쌓이게 됩니다.

popUpTo 와 popUpToInclusive

popUpTo와 popUpToInclusive는 대상을 일일이 pop하지 않고 관련된 모든 대상을 백스택에서 pop할 수 있게 해줍니다.

<action>태그안에 app:popUpTo와 app:popUpToInclusive를 추가하여 편하게 사용할 수 있습니다

app:popUpTo=”destination”를 추가하면 action이 실행될 때 백 스택의 destination까지의 stack들이 pop 됩니다.

app:popUpToInclusive=”true”를 추가하면 pupUpTo에 지정된 destination을 포함하여 stack들이 pop 됩니다.

예시 그래프를 통해 설명해보겠습니다.

프래그먼트 1, 2, 3, 4, 5 가 순환되는 흐름입니다. 여기서 3 → 4로 넘어가는 action에 popUpTo=one을 해보겠습니다.

one -> two -> three 로 이동하고 one 까지의 two, three는 pop이 되어 스택에는 one과 four만 남게 됩니다. 따라서 one 에서 뒤로가기를 누르면 앱이 종료됩니다.

popUpToInclusive=true 를 추가하면 one 또한 스택에서 사라집니다

one -> two -> three 로 이동하고 one, two, three 모두 스택에서 pop 되어 four 화면에서 뒤로가기를 누르면 앱이 종료됩니다.

popUpTo에 설정된 destination이 백 스택에 여러개 쌓여 있을 때 최상단의 destination이 설정되므로 순환이 되는 흐름에서 돌아오는 action에 popUpToInclusive=true를 설정해주지 않으면 똑같은 화면이 두개가 쌓이게 됩니다.

5->1 의 action에서 (popUpTo)와 (popUpTo & popUpToInclusive=”ture”)의 back stack
왼쪽: popUpTo만 적용하여 one이 두개 남음, 오른쪽: popUpToInclusive=”true”를 추가하여 one이 한개만 남음

popUpTo와 비슷한 기능을 popBackStack(destinationId, inclusive)를 통해 사용할 수 있습니다. 특정 화면에서 뒤로가기를 눌렀을 때 이전의 작업들을 취소하고 첫화면으로 돌아가는 경우에 블로그 위에서 언급한

‘회원가입시 비밀번호 설정에서 뒤로가면 인증번호 확인이 아닌 이메일 인증 화면으로 돌아가고 싶었습니다.’

의 경우를 예로 들 수 있습니다.

NavController.popBackStack()

popBackStack()에 아무 옵션을 주지 않으면 해당 화면만 pop됩니다. 하지만 옵션을 추가하면 popUpTo와 비슷하게 사용할 수 있습니다.

destination까지의 stack들을 pop 해주는데 마찬가지로 inclusive 옵션을 주어 포함시켜서 pop 할 지를 정할 수 있습니다.

NavOptions

또한 navigate(resId, args, navOptions)에서 navOptions을 통해 스택을 관리할 수 있습니다.

NavOptions를 보면 여러 상태들이 있는데 스택과 관련된 singleTop, popUpToId, popUpToInclusive, popUpToSaveState등을 볼 수 있습니다.

각각의 상태의 초기값은 아래와 같습니다.

각 상태들은 Builder()를 통해 세팅할 수 있습니다.

  • singleTop : 싱글탑은 최상단에 있는 destination과 전환 될 destination이 같을 때, 새로운 인스턴스를 생성하지 않고 스택에 있는 destination을 재사용하는것을 의미하는데 setLaunchSingleTop()을 통해 세팅이 가능합니다.
  • popUpTo : popUpTo와 관련된 상태는 setPopUpTo()를 통해 세팅이 가능합니다. 사용 방법은 <action> 태그에 사용된 popUpTo와 동일합니다.

그럼 간단하게 활용해 봅시다.

five에서 one으로 돌아올 때 one위의 모든 스택들을 pop하려면 아래와 같은 코드로 구현할 수 있습니다.

돌아올 화면을 재사용하길 원한다면 singleTop을 true로 바꿔주면 됩니다.

State와 관련된 이야기는 아래서 짧게 다뤄보겠습니다.

popUpToSaveState 와 restoreSaveState

는 다음에~

--

--