프래그먼트 트랜잭션

런타임 시 FragmentManager는 사용자 상호작용의 응답으로 프래그먼트와 함께 작업을 추가하거나 삭제, 교체하는 등 기타 작업을 할 수 있습니다. 커밋하는 각 프래그먼트 변경사항 집합을 트랜잭션이라고 합니다. 개발자는 FragmentTransaction 클래스에 의해 제공되는 API를 사용하여 이 트랜잭션 내에서 실행할 작업을 지정할 수 있습니다. 여러 작업을 단일 트랜잭션으로 그룹화할 수 있습니다. 예를 들어 한 트랜잭션에서 여러 개의 프래그먼트를 추가하거나 바꿀 수 있습니다. 이 같은 그룹화는 분할 뷰를 사용할 때처럼 한 화면에 여러 개의 동위 프래그먼트가 표시되는 경우에 유용합니다.

FragmentManager에서 관리하는 백 스택에 각 트랜잭션을 저장할 수 있습니다. 그렇게 하면 사용자가 활동에서 뒤로 이동하는 것처럼 프래그먼트 변경사항에서 뒤로 이동할 수 있습니다.

다음 예에 나와 있는 것처럼 beginTransaction()을 호출하여 FragmentManager에서 FragmentTransaction의 인스턴스를 가져올 수 있습니다.

Kotlin

val fragmentManager = ...
val fragmentTransaction = fragmentManager.beginTransaction()

자바

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

FragmentTransaction의 마지막 호출은 트랜잭션을 커밋해야 합니다. commit() 호출은 FragmentManager에 모든 작업이 트랜잭션에 추가되었음을 알려줍니다.

Kotlin

val fragmentManager = ...
// The fragment-ktx module provides a commit block that automatically
// calls beginTransaction and commit for you.
fragmentManager.commit {
    // Add operations here
}

자바

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

// Add operations here

fragmentTransaction.commit();

프래그먼트 상태 변경의 재정렬 허용

FragmentTransactionsetReorderingAllowed(true)를 사용해야 합니다.

Kotlin

supportFragmentManager.commit {
    ...
    setReorderingAllowed(true)
}

자바

FragmentManager fragmentManager = ...
fragmentManager.beginTransaction()
    ...
    .setReorderingAllowed(true)
    .commit();

동작 호환성을 위해 재정렬 플래그는 기본적으로 사용되지 않습니다. 그러나 FragmentManagerFragmentTransaction을 올바로 실행할 수 있도록 허용해야 하며, 프래그먼트 관리자가 백 스택에서 동작하고 애니메이션과 전환을 실행하는 경우에는 더욱 그러합니다. 이 플래그를 사용 설정하면 여러 트랜잭션이 함께 실행될 때 중간 프래그먼트(즉, 추가된 직후 교체된 프래그먼트)에 수명 주기 변경이 발생하지 않거나 애니메이션 또는 전환이 실행되지 않습니다. 참고로, 이 플래그는 트랜잭션의 초기 실행은 물론, popBackStack()으로 트랜잭션을 반전시키는 작업에도 영향을 미칩니다.

프래그먼트 추가 및 삭제

FragmentManager에 프래그먼트를 추가하려면 트랜잭션에서 add()를 호출합니다. 이 메서드는 프래그먼트의 컨테이너 ID와 추가하려는 프래그먼트의 클래스 이름을 수신합니다. 추가된 프래그먼트는 RESUMED 상태로 전환됩니다. 컨테이너를 뷰 계층 구조의 일부인 FragmentContainerView로 사용하는 것이 좋습니다.

호스트에서 프래그먼트를 삭제하려면 remove()를 호출하고 findFragmentById() 또는 findFragmentByTag()를 통해 프래그먼트 관리자에서 가져온 프래그먼트 인스턴스를 전달합니다. 프래그먼트의 뷰가 이전에 컨테이너에 추가되었다면, 이 시점에서 이 뷰가 컨테이너에서 삭제됩니다. 삭제된 프래그먼트는 DESTROYED 상태로 전환됩니다.

replace()를 사용하여 컨테이너의 기존 프래그먼트를 개발자가 제공할 새 프래그먼트 클래스의 인스턴스로 바꿀 수 있습니다. replace()를 호출하는 것은 컨테이너의 프래그먼트와 함께 remove()를 호출하거나 동일한 컨테이너에 새 프래그먼트를 추가하는 것과 같습니다.

다음 코드 스니펫은 특정 프래그먼트를 다른 프래그먼트로 바꾸는 방법을 보여줍니다.

Kotlin

// Create new fragment
val fragmentManager = // ...

// Create and commit a new transaction
fragmentManager.commit {
    setReorderingAllowed(true)
    // Replace whatever is in the fragment_container view with this fragment
    replace<ExampleFragment>(R.id.fragment_container)
}

자바

// Create new fragment and transaction
FragmentManager fragmentManager = ...
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.setReorderingAllowed(true);

// Replace whatever is in the fragment_container view with this fragment
transaction.replace(R.id.fragment_container, ExampleFragment.class, null);

// Commit the transaction
transaction.commit();

이 예에서 ExampleFragment의 새 인스턴스는 현재 R.id.fragment_container로 식별된 레이아웃 컨테이너에 있는 프래그먼트(있는 경우)를 바꿉니다.

기본적으로 FragmentTransaction에서 변경한 내용은 백 스택에 추가되지 않습니다. 이러한 변경사항을 저장하려면 FragmentTransaction에서 addToBackStack()를 호출하면 됩니다. 자세한 내용은 프래그먼트 관리자를 참조하세요.

커밋이 비동기식임

commit()을 호출하더라도 트랜잭션이 즉시 실행되지는 않습니다. 대신 트랜잭션이 가능한 빨리 기본 UI 스레드에서 실행되도록 예약됩니다. 그러나 필요한 경우 commitNow()를 호출하여 UI 스레드에서 프래그먼트 트랜잭션을 즉시 실행할 수 있습니다.

참고로, commitNowaddToBackStack과 호환되지 않습니다. 또는 commit() 호출로 제출된 모든 대기중 FragmentTransactions 중에서 executePendingTransactions()을 호출해 아직 실행되지 않은 것을 실행할 수 있습니다. 이 방법은 addToBackStack에도 적용 가능합니다.

대부분의 사용 사례에서는 commit()만 있으면 됩니다.

작업 순서가 중요함

특히 setCustomAnimations()를 사용할 경우 FragmentTransaction 내에서의 작업 순서가 중요합니다. 이 메서드는 메서드를 따르는 모든 프래그먼트 작업에 지정된 애니메이션을 적용합니다.

Kotlin

supportFragmentManager.commit {
    setCustomAnimations(enter1, exit1, popEnter1, popExit1)
    add<ExampleFragment>(R.id.container) // gets the first animations
    setCustomAnimations(enter2, exit2, popEnter2, popExit2)
    add<ExampleFragment>(R.id.container) // gets the second animations
}

자바

getSupportFragmentManager().beginTransaction()
        .setCustomAnimations(enter1, exit1, popEnter1, popExit1)
        .add(R.id.container, ExampleFragment.class, null) // gets the first animations
        .setCustomAnimations(enter2, exit2, popEnter2, popExit2)
        .add(R.id.container, ExampleFragment.class, null) // gets the second animations
        .commit()

프래그먼트의 수명 주기 제한

FragmentTransactions은 트랜잭션 범위 내에 추가된 개별 프래그먼트의 수명 주기 상태에 영향을 줄 수 있습니다. FragmentTransaction을 생성할 때 setMaxLifecycle()은 주어진 프래그먼트의 최대 상태를 설정합니다. 예를 들어 ViewPager2setMaxLifecycle()을 사용하여, 화면을 벗어난 프래그먼트를 STARTED 상태로 제한합니다.

프래그먼트의 뷰 표시 및 숨기기

FragmentTransaction 메서드 show()hide()를 사용하여 컨테이너에 추가된 프래그먼트의 뷰를 표시하거나 숨길 수 있습니다. 이러한 메서드는 프래그먼트의 수명 주기에 영향을 주지 않는 상태에서 프래그먼트 뷰의 공개 상태를 설정합니다.

프래그먼트 내에서 뷰 가시성을 전환하는 데 프래그먼트 트랜잭션을 사용할 필요가 없기는 하지만, 공개 상태 변경을 백 스택의 트랜잭션에 연결하려는 경우 이러한 메서드가 유용합니다.

프래그먼트 연결 및 분리

FragmentTransaction 메서드 detach()는 프래그먼트를 UI에서 분리하고 뷰 계층 구조를 소멸시킵니다. 프래그먼트는 백 스택에 배치될 때와 동일한 상태(STOPPED)로 유지됩니다. 즉, 프래그먼트는 UI에서 삭제되었지만 프래그먼트 관리자에 의해 계속 관리됩니다.

attach() 메서드는 이전에 분리된 프래그먼트를 다시 연결합니다. 그러면 뷰 계층 구조가 다시 생성되고 UI에 연결되어 표시됩니다.

FragmentTransaction이 작업의 단일 원자형 집합으로 처리되므로, 동일한 트랜잭션의 동일한 프래그먼트 인스턴스에서 detachattach를 모두 호출하면 사실상 서로 상쇄됩니다. 따라서 프래그먼트 UI가 소멸되고 즉시 재생성되는 것이 방지됩니다. commit()을 사용할 때 프래그먼트를 분리하고 바로 다시 연결하려면 executePendingOperations()로 분리된 개별 트랜잭션을 사용하세요.