Fragment를 추가, 삭제, 교체, 백스택에 추가 등 트랜잭션을 실행하는 프래그먼트를 관리하는 역할을 합니다. 그 외에 Fragment를 찾을수 도 있고, Activity 또는 Fragment와 값을 주고 받을 수 있는 result listener 기능도 있습니다.
프래그먼트의 트랜잭션 관리를 쉽고 편하게 도와주는 Android Jetpack라이브러리의 Navigation 사용이 권장된다고 합니다.
Acrivity에서 접근방법
supportFragmentManager
Fragment에서 접근
Fragment는 생성될때 또 다른 개인적인 FragmentManager를 갖게 됩니다. 이를 childFragmentManager
Activity에 있는 FragmentManager를 접근하려면 parentFragmentManager
FragmentManager로 Fragment를 추가/삭제/교체를 도와주는 역할이
FragmentTransaction 입니다.
각 사용자가 commit 하게되는 프래그먼트의 변경 사항의 집합을 transaction이라고 부르며, FragmentTransaction 클래스에 의해 제공되는 API를 사용하여 트랜잭션 내부에서 무엇을 할지 지정할 수 있다.
supportFragmentManager.beginTransaction()
commit()
호출 해야 합니다.supportFragmentManager
.beginTransaction()
.add(ExampleFragment(), "tag")
.commit()
supportFragmentManager.commit {
add(ExampleFragment(), "tag")
}
commit()
commitAllowingStateLoss()
commitNow()
commitNowAllowingStateLoss()
기본적으로 commit() 사용을 권장하고 있고, commit()과 commitNow()의 차이점은 commit()
은 트랜잭션의 커밋을 예약하고 즉시 실행되지 않습니다. 메인스레드의 작업 스케줄로 추가 되며, commitNow()
는 즉시 실행되는 동기 방식입니다.
이전에는 commit()을 한 후 executePendingTransactions()를 불러 트랜잭션
실행을 기다리는 방법이 있었지만, 이 방법은 자신과는 관계없는 모든 트랜잭션에 대해서도
그 자리에서 실행해 버리기 때문에 그 점에서 자신만 즉시 실행하는 commitNow() 쪽이
낫다는 것입니다. 따라서 commitNow()는 사용자가 실제 실행하고자 하는 것보다 더 많은
트랜잭션을 실수로 실행할 수 없도록 도와줍니다.
❗️주의할 점은 백스택에 추가하는 addToBackStack()
을 commitNow()에서 사용할 수 없다는 것 입니다. 그 이유는 commit()으로 비동기로 백스택에 트랜잭션을 추가하고 commitNow()로 즉각적으로 백스택에 추가한다면 백스택에 순서 보장이 안되기 때문입니다.
commit 과 commitAllowingStateLoss 는 구현에 있어서 거의 비슷하다고 볼 수 있습니다. 유일한 차이는 commit이 FragmentManager 가 자신의 state 를 저장했는지 확인한다는 것입니다. 만약 이미 state 를 저장했다면
IllegalStateException
를 던집니다.
그렇다면 commitAllowingStateLoss 는 어떤 state 를 잃는(loss) 다는 것일까요? 정답은 FragmentManager 의 state 그리고
onSaveInstanceState
이후에 추가, 제거된 Fragment들의 state 를 잃을 수 있다는 것입니다.
요약하면 onSaveInstanceState
이후 commit()을 하게되면 트랜잭션 상태를 잃어버려 사용자 입장에서 원하는 동작이 안될수 있습니다.
위 표를 보시면 안드로이드 버전 3.0 허니콤 이후 lifecycle에 변경이 있었고,
onStop()
정확히는 super.onStop() 이후commit()
을 호출하면Exception
이 발생합니다. onPause와 onStop의 사이 또는 onPause이전에 호출되어야 합니다. 그래서 state를 잃어버려도 괜찮은 경우 Exception을 피하고 싶을때commitAllowingStateLoss()
을 사용할 수 있습니다.
만약 API를 호출하거나 비동기 작업을 호출하고 그에 callback으로 commit()을 수행한다고 하면 작업 도중 홈키로 앱이 백그라운드 상태에 간다면
Exception
이 발생하게 됩니다.
마지막으로 FragmentManager로 Activity에 포함된 프래그먼트들 또는 Fragment내에 있는 Fragment를 찾는 2가지 방법이 있습니다.
supportFragmentManager.findFragmentById(R.id.container1)
supportFragmentManager.findFragmentByTag("tag")