FragmentManager와 ChildFragmentManager

허니컴(Honeycomb)부터 액티비티나 프레그먼트 안에 프레그먼트를 추가할 수 있다. 이 프레그먼트 객체를 관리하는 것이 FragmentManager다. 프레그먼트 전반에 대한 소개는 공식문서를 참고하고, 여기서는 종종 헷갈려하는 FragmentManager와 일명 ChildFragmentManager의 차이점에 대해서만 설명한다.

먼저 ChildFragmentManager라는 용어부터 짚고 넘어가자. ChildFragmentManager라는 클래스는 따로 없다.  대신, Activity.getFragmentManager()나 Fragment.getFragmentManager()에서 반환하면 FragmentManager(이하 FM), Fragment.getChildFragmentManager() 메소드에서 반환되는 FragmentManager 객체를 ChildFragmentManager(이하 CFM)라고 보통 부른다.

FM과 CFM 모두 FragmentManager 클래스의 객체이니, 동작은 유사하다. 하지만, 실제 사용 시에는 헷갈린다.

  • FM은 액티비티, 액티비티 속 프레그먼트(이하 자식 프레그먼트) 그리고 프레그먼트 속 프레그먼트(이하 손자 프레그먼트)가 모두 사용할 수 있다.
  • CFM은 프레그먼트(자식)와 프레그먼트 속 프레그먼트(손자)들만 사용할 있다.
  • FM에서 관리되는 손자 프레그먼트라면, getFragmentManager()는 액티비티의 getFragmentManager()와 동일한 객체를 반환한다.
  • CFM에서 관리되는 손자 프레그먼트라면, getFragmentManager()는 부모(액티비티의 자식) 프레그먼트의 getChildFragmentManager()와 동일한 객체를 반환한다.

위와 같이 FM과 CFM은 다른 객체이므로 FragmentManager.findFragmentBy…() 메소드의 결과도 다르다. FM이 관리하는 프레그먼트는 FM에서, CFM에서 관리하는 프레그먼트는 CFM에서 찾아야할 것이다.

번거롭게 왜 두개를 유지하는 것일까? API 11에는 getFragmentManager()만 있었다. 그 후, API 17부터 getChildFragmentManager()가 추가된다. 두 개로 유지하는 것의 장점은 remove() 메소드를 통해 프레그먼트를 제거할 때 더 잘 알 수 있다. (여기서 제거란 화면에서 보이는지 여부가 아닌, …onDestroy(), onDetach()로 이어지는 프레그먼트 객체 소멸을 말한다.)

액티비티-자식프레그먼트-손자 프레그먼트의 계층구조를 가진 액티비티가 있다. 여기서 자식 프레그먼트를 제거한다고 해보자. 손자 프레그먼트가 FM에서 관리된다면 자식 프레그먼트만 제거된다.  반면, 자식 프레그먼트의 CFM을 통해 손자 프레그먼트가 관리된다면, 손자프레그먼트가 먼저 제거된 후 자식 프레그먼트가 제거된다. 이는 프레그먼트의 계층구조로 인해 오는 관리의 어려움을 쉽게 만들 수 있다.

마지막으로, 위와 같은 구조가 startActivityForResult()의 결과에도 영향을 미칠까? 그렇지 않다. 어떤 액티비티나 프레그먼트에서 호출하든, startActivityForResult()의 결과를 onActivityResult()를 통해 받을 수 있다.  FM이나 CFM 어디에서 관리하든 상관 없이 startActivityResult()를 호출했던 프레그먼트로 결과가 반환된다. Fragment.onActivityResult()의 동작도 헷갈리는 부분이 있다면 이 글을 참고하자.

그 밖에

  • support library의 FragmentActivity를 상속받아 만든 액티비티의 경우는 getSupportFragmentManager()를 통해 FragmentManager 객체를 얻는다.
  • Activity 클래스의 getFragmentManager()는 P OS부터 deprecated 된다.

참고