본문 바로가기

안드로이드/JetPack

[안드로이드] 프래그먼트 스택 (feat. 네비게이션)

개요

안드로이드에서 뷰나 액티비티와 같은 컴포넌트들은 스택으로 관리된다. A에서 B, C화면 순으로 이동하면 A, B, C 순으로 스택에 남아있고 top은 C를 가리키고 있으며, C가 파괴되면 B로 top이 이동하여 화면에 보이는 방식이다.

 

Jetpack의 네비게이션 컴포넌트에서 스택의 관리는 아래와 같다.

 

스택에 추가

findNavController().navigate(VIEW)

위는 네비게이션 컨트롤러를 통해 다른 뷰로 이동하는 코드이다. 위 코드가 수행될 경우 백 스택에 현재 뷰가 저장된다.

 

popUpTo, popUpToInclusive

위에서 다른 뷰로 이동할 때 백 스택에서 현재 대상을 팝하도록 선택할 수 있다. 예를 들어, 앱에서 로그인 과정이 있다면 사용자가 로그인했을 때 사용자가 뒤로 버튼을 눌러도 로그인 과정으로 돌아가지 않도록 로그인과 관련된 모든 대상을 백 스택에서 제거(pop)해야 한다.

 

한 대상에서 다른 대상으로 이동할 때 대상을 제거(pop)하려면 app:popUpTo 속성을 연결된 <action> 요소에 추가한다. app:popUpTo는 navigate() 호출의 일부로 백 스택에서 몇 개의 대상을 팝하도록 탐색 라이브러리에 알려준다. 속성값은 스택에 남아 있어야 하는 가장 최근 대상의 ID이다.

 

또한, app:popUpToInclusive="true"를 포함하여 app:popUpTo에 지정된 대상이 백 스택에서 삭제될 수도 있다는 것을 나타낼 수도 있다.

 

예시

앱에 A, B, C 세 개의 대상과 A에서 B로, B에서 C로, C에서 A로 연결되는 작업이 있다고 가정하면. 이에 상응하는 네비게이션 그래프는 다음과 같다.

 

각 탐색 작업에서 대상이 백 스택에 추가된다. 이 과정을 통해 반복적으로 이동한다면 백 스택에는 각 대상의 여러 세트(A, B, C, A, B, C, A 등)가 존재한다. 이러한 반복을 피하려면 다음 예와 같이 대상 C에서 대상 A로 이동하는 작업에 app:popUpTo app:popUpToInclusive를 지정하면 된다.

 

<fragment
    android:id="@+id/c"
    android:name="com.example.myapplication.C"
    android:label="fragment_c"
    tools:layout="@layout/fragment_c">

    <action
        android:id="@+id/action_c_to_a"
        app:destination="@id/a"
        app:popUpTo="@+id/a"
        app:popUpToInclusive="true"/>
</fragment>

C에 도달한 후 백 스택은 각 대상(A, B, C)의 한 인스턴스를 포함한다. A로 다시 이동하면 A도 popUpTo하며 이는 이동하는 동안 B와 C를 스택에서 삭제하는 것을 의미한다. app:popUpToInclusive="true"인 경우 스택에서 첫 번째 A도 팝하여 효과적으로 스택을 제거한다. app:popUpToInclusive를 사용하지 않는다면 백 스택은 대상 A 인스턴스 두 개를 포함하게 된다.

 

아래와 같이 옵션을 만드는 프로그래밍 방식으로도 가능하다.

val directions = NavMainDirections.actionGlobalCommunityFragment()
findNavController().popBackStack()
findNavController().navigate(directions)

뒤로 가기 버튼을 눌렀을 경우 현재 프래그먼트를 백 스택에서 제거한다.