본문 바로가기

Programming/Android

Fragment - 3. 관리

프래그먼트 관리


액티비티 내의 프래그먼트를 관리하려면 FragmentManager를 사용해야 합니다. 이것을 가져오려면 액티비티에서 getFragmentManager()를 호출하세요.

FragmentManager를 가지고 할 수 있는 여러 가지 일 중에 예를 들면 다음과 같습니다.

  • 액티비티 내에 존재하는 프래그먼트를 findFragmentById()로 가져오기(액티비티 레이아웃 내에서 UI를 제공하는 프래그먼트의 경우) 또는 findFragmentByTag()로 가져오기(UI를 제공하거나 하지 않는 프래그먼트의 경우).
  • popBackStack()을 사용하여 프래그먼트를 백 스택에서 꺼냅니다(사용자가 Back 명령을 시뮬레이션).
  • 백 스택에 변경 내용이 있는지 알아보기 위해 addOnBackStackChangedListener()로 리스너를 등록합니다.

이와 같은 메서드와 그 외 다른 메서드에 대한 자세한 정보는 FragmentManager 클래스 관련 문서를 참조하세요.

이전 섹션에서 설명한 바와 같이 FragmentManager를 사용해서도 FragmentTransaction 을 열 수 있습니다. 이렇게 하면 프래그먼트 추가 및 제거 등 트랜잭션을 수행할 수 있게 해줍니다.

프래그먼트 트랜잭션 수행


액티비티에서 프래그먼트를 사용하는 경우 특히 유용한 점은 사용자 상호작용에 응답하여 추가, 제거, 교체 및 다른 작업을 수행할 수 있다는 것입니다. 액티비티에 커밋한 변경 내용의 집합을 트랜잭션이라고 하며, 이것을 수행하려면 FragmentTransaction 내의 API를 사용하면 됩니다. 해당 액티비티가 관리하는 백 스택에 행해진 각 트랜잭션을 저장할 수도 있습니다. 이렇게 하면 사용자가 프래그먼트 변경 내역을 거쳐 뒤로 탐색할 수 있습니다(액티비티를 통과해 뒤로 탐색하는 것과 비슷합니다).

FragmentTransaction의 인스턴스를 FragmentManager로부터 가져오는 방법은 다음과 같습니다.

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

각 트랜잭션은 동시에 수행하고자 하는 변경 집합입니다. 주어진 트랜잭션에 대해 수행하고자 하는 모든 변경 사항을 설정하려면 add()remove(), 및 replace()와 같은 메서드를 사용하면 됩니다. 그런 다음, 트랜잭션을 액티비티에 적용하려면 반드시 commit()을 호출해야 합니다.

하지만 commit()을 호출하기 전에 먼저 호출해야 할 것이 있습니다. 바로 addToBackStack()입니다. 이렇게 해야 트랜잭션을 프래그먼트 트랜잭션의 백 스택에 추가할 수 있습니다. 이 백 스택을 액티비티가 관리하며, 이를 통해 사용자가 이전 프래그먼트 상태로 되돌아갈 수 있습니다. 이때 Back 버튼을 누르면 됩니다.

예를 들어 다음은 한 프래그먼트를 다른 것으로 교체하고 이전 상태를 백 스택에 보존하는 방법을 보여줍니다.

// Create new fragment and transaction
Fragment newFragment = new ExampleFragment();
FragmentTransaction transaction = getFragmentManager().beginTransaction();

// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack
transaction
.replace(R.id.fragment_container, newFragment);
transaction
.addToBackStack(null);

// Commit the transaction
transaction
.commit();

이 예시에서는 newFragment가 현재 레이아웃 컨테이너에서 식별된 프래그먼트(있는 경우)를 R.id.fragment_container ID로 교체합니다. addToBackStack()를 호출함으로써 교체 트랜잭션이 백 스택에 저장되므로, 사용자가 Back 버튼을 눌러 트랜잭션을 되돌리고 이전 프래그먼트를 다시 가져올 수 있습니다.

트랜잭션에 여러 개의 변경을 추가하고(예: 또 다른 add() 또는 remove()), addToBackStack()을 호출하면, commit()을 호출하기 전에 적용된 모든 변경 내용이 백 스택에 하나의 트랜잭션으로 추가되며, Back 버튼을 누르면 모두 한꺼번에 되돌려집니다.

FragmentTransaction에 변경 내용을 추가하는 순서는 중요하지 않습니다. 다만 다음과 같은 예외가 있습니다.

  • commit()을 마지막으로 호출해야 합니다.
  • 같은 컨테이너에 여러 개의 프래그먼트를 추가하는 경우, 이를 추가하는 순서가 이들이 뷰 계층에 나타나는 순서를 결정 짓습니다.

프래그먼트를 제거하는 트랜잭션을 수행하면서 addToBackStack()을 호출하지 않는 경우, 해당 프래그먼트는 트랜잭션이 적용되면 소멸되고 사용자가 이를 되짚어 탐색할 수 없게 됩니다. 반면에 프래그먼트를 제거하면서 addToBackStack()을 호출하면, 해당 프래그먼트는 중단되고 사용자가 뒤로 탐색하면 재개됩니다.

팁: 각 프래그먼트 트랜잭션에 대해 전환 애니메이션을 적용하려면 커밋하기 전에 setTransition()을 호출하면 됩니다.

commit()을 호출해도 그 즉시 트랜잭션을 수행하지는 않습니다. 그보다는, 액티비티의 UI 스레드("주요" 스레드)를 스레드가 할 수 있는 한 빨리 이 트랜잭션을 수행하도록 일정을 예약하는 것에 가깝습니다. 하지만 필요한 경우 UI 스레드로부터 executePendingTransactions()를 호출하면 commit()이 제출한 트랜잭션을 즉시 실행할 수 있습니다. 트랜잭션이 다른 스레드의 작업에 대한 종속성이 아니라면 굳이 이렇게 해야만 하는 것은 아닙니다.

주의: 트랜잭션을 커밋할 때 commit()을 사용해도 되는 것은 (사용자가 액티비티를 떠날 때) 액티비티가 그 상태를 저장하기 전뿐입니다. 그 시점 이후에 적용하려고 하면 예외가 발생합니다. 이것은 액티비티를 복원해야 하는 경우 적용 이후의 상태가 손실될 수 있기 때문입니다. 커밋이 손실되어도 괜찮은 상황이라면, commitAllowingStateLoss()를 사용하세요.