Sitemap
hongbeomi dev

hongbeomi 개발블로그

popBackStack vs navigateUp

5 min readJan 24, 2025

--

Compose Navigation의 뒤로가기

Press enter or click to view image in full size
Photo by The Pop'd Shop on Unsplash

Compose Navigation을 사용하여 화면 전환을 관리한다면, 백스택(back stack)에 대해 알고 계실 것입니다. 백스택은 유저가 화면을 탐색할 때 쌓이는 스택을 의미하며, 유저가 화면을 이탈한 후 이전 화면으로 돌아가고자 할 때 활용됩니다. 백스택은 앱 내에 여러 개가 존재할 수 있으며, 뒤로가기 동작을 프로그래밍 방식으로 구현하기 위해 NavHostControllerpopBackStack() 함수나 navigateUp() 함수를 사용할 수 있습니다. 이 두 함수는 현재 백스택의 화면을 pop하여 뒤로 가기를 수행한다는 점에서 유사하지만, 특정 상황에서는 서로 다른 결과를 초래할 수 있습니다.

Issue

B 화면에서 빠르게 popBackStack을 호출 하면 발생하는 버그

예를 들어, B 화면에서 popBackStack을 호출하는 버튼이 있다고 가정해보겠습니다. 유저가 A 화면에서 B 화면으로 이동한 뒤, B 화면에서 해당 버튼을 빠르게 두 번 이상 누른다면, 유저는 아무것도 표시되지 않는 흰 화면을 보게 될 수 있습니다. 이는 B 화면에서 A 화면으로 전환될 때 트랜지션 애니메이션이 실행되는데, 이 과정에서 popBackStack이 두 번 이상 호출되면서 백스택의 엔트리 전체가 pop되기 때문입니다. 이렇게 되면 백스택을 유지할 방법이 없어집니다.

이 문제를 해결하려면 navigateUp을 대신 사용하거나, popBackStack을 호출하는 버튼 이벤트에 delay를 추가하는 등의 대응이 필요합니다.

Why?

이 문제는 popBackStack 함수의 동작 원리에 의해 발생합니다. popBackStacknavigateUp은 각각 아래와 같은 특징을 가지고 있습니다.

  • popBackStack : 백스택 큐를 확인한 뒤, 비어 있지 않다면 내부적으로 해당 백스택의 pop 동작을 수행합니다. 하지만 현재 백스택 상태를 인지하지 못하기 때문에, 위와 같은 상황에서 불안정한 동작을 보일 수 있습니다.
@MainThread
public open fun popBackStack(): Boolean {
return if (backQueue.isEmpty()) {
// 백스택 큐를 확인
false
} else {
// 내부적으로 pop 동작 수행
popBackStack(currentDestination!!.id, true)
}
}
  • navigateUp : popBackStack과 달리 현재 백스택을 인지하고, 스택의 맨 위에 있는 화면만 pop합니다. 이 함수는 빠르게 두 번 호출되더라도 동일한 화면이 스택의 맨 위에 존재하기 때문에 안정적인 동작을 보장합니다. 또한, 현재 화면이 딥링크로 열린 경우 navigateUp을 호출하면 이전 앱으로 돌아가지만 popBackStack을 호출하면 앱의 백스택으로만 이동하는 차이도 존재합니다.
@MainThread
public open fun navigateUp(): Boolean {
// 백스택이 하나만 존재하는 경우, 딥링크로 인해 실행된 작업인지 체크하고 돌아가려고 시도
if (destinationCountOnBackStack == 1) {
val extras = activity?.intent?.extras
if (extras?.getIntArray(KEY_DEEP_LINK_IDS) != null) {
return tryRelaunchUpToExplicitStack()
} else {
return tryRelaunchUpToGeneratedStack()
}
} else {
// 그렇지 않다면 popBackStack 호출
return popBackStack()
}
}

공식 문서에서는 popBackStack이 기기 하단의 네비게이션 영역에 있는 뒤로 가기 버튼과 대응하며, navigateUp은 앱 바의 “<-” 버튼과 대응한다고 설명하고 있습니다. 따라서 상황에 따라 적절한 API를 선택해서 의도치 않은 동작을 방지하는 것이 좋겠습니다.

--

--

No responses yet