바텀 네비게이션 설정을 하는데, 바텀네비가 아닌 다른 외부 버튼으로 프래그먼트를 이동할때 바텀 네비게이션이 원하는대로 동작하지 않게 된다.
이유를 찾다가 백스택에 대해서 알게 되었다.
액티비티나 프래그먼트의 이력을 관리하는 스택(stack) 구조의 메커니즘이다
프래그먼트(혹은 액티비티)에서 다른 프래그먼트로 이동하게 되면 이전 화면을 BackStack에 추가하게 되는데, 이를통해서 사용자가 뒤로 가기 버튼을 누를 때 이전 화면으로 돌아갈 수 있게 된다.
그래서 이게 바텀 네비게이션이 제대로 작동안하는 것과 무슨 연관이 있냐?
바텀 네비게이션을 통해 이동하는 각 프래그먼트는 프래그먼트 별로 독립적인 백스택을 갖는데
그림에서 Home프래그먼트에서 네비게이션을 이용해 New프래그먼트로 이동시 New프래그먼트 뒤에는 홈프래그먼트 백스택이 추가 된다.
그리고 다시 홈버튼을 눌렀을때 홈프래그먼트에 new프래그먼트가 백스택으로 추가 되지 않고 백스택에 있는 홈 프래그먼트로 돌려보내게 되는 것 이다
그런데 네비게이션외에 외부에서 프래그먼트를 이동시키면 문제가 발생하는데
외부 버튼에서 프래그먼트를 생성한경우 기존 프래그먼트는 백스택으로 빠졌는데 네비게이션에선 그걸 인지하지 못해 상태가 업데이트 되지 않는다.
그래서 하던대로 New프래그먼트에서 홈버튼을 눌렀을때 백스택에 있는 이전 상태로 보내게 되고 외부버튼으로 만들어진 프래그먼트로 돌아가게 되는 것 이다
이를 해결하기 위해선 따로 관리를 해줘야한다
바텀 네비게이션은 네비게이션을 정의해놓은 xml이 있는데 이를 통해 액션을 관리해줄수 있다.
<fragment
android:id="@+id/navigation_home"
android:name="com.example.pintube.ui.home.HomeFragment"
android:label="@string/title_home"
tools:layout="@layout/fragment_home" >
<action
android:id="@+id/action_navigation_home_to_navigation_detail"
app:destination="@id/navigation_detail"
app:popUpTo="@id/navigation_home"
app:popUpToInclusive="true" />
<action
android:id="@+id/action_navigation_home_to_navigation_mypage"
app:destination="@id/navigation_mypage"
app:popUpToInclusive="true" />
</fragment>
여기서 popUpTo와 popUpToInclusive를 통해서 관리 해 줄수 있는데
popUpTo는 이동하면 백스택에서 시작지점으로 지정된 대상 이전까지 모든 백스택을 제거한다
그리고 popUpToInclusive를 True로해 지정된 대상 여기서는 navigation_home도 백스택에서 제거한다.
이렇게 되면 백스택이 꼬이지 않게 되어 다른 페이지를 가도 홈 프래그먼트를 문제없이 호출 할 수 있다.
하지만 디테일 페이지에서 뒤로가기 버튼을 눌렀을 경우 백스택에 등록된 프래그먼트가 없으니 앱이 종료되게 되는 문제가 있는데
override fun onBackPressed() {
val currentFragment = navHostFragment.childFragmentManager.fragments[0]
if (currentFragment is DetailFragment) {
navController.navigate(
resId = R.id.action_navigation_detail_to_navigation_home,
)
} else {
super.onBackPressed()
}
액티비티에서 뒤로가기 작동시 액션을 통해 백스택을 지우며 home프래그먼트로 이동시켜 이를 해결 할 수 있다.