[Android] Fragment Lifecycle

leeeha·2023년 4월 14일
0

안드로이드

목록 보기
4/6
post-thumbnail

Fragment lifecycle

각 프래그먼트 인스턴스는 자기 자신의 생명주기를 가집니다. 사용자가 앱을 탐색하고 상호 작용할 때 프래그먼트는 추가, 제거 및 화면에 들어가거나 나올 때 그들의 생명주기 내에서 다양한 상태로 전환됩니다.

생명주기를 관리하기 위해서, 프래그먼트는 LifecycleOwner 라는 인터페이스를 구현하고 있으며, 개발자는 getLifecycle() 메서드로 Lifecycle 객체에 접근할 수 있습니다.

각각의 생명주기 상태는 Lifecycle.State 라는 enum 클래스로 표현됩니다.

  • INITIALIZED
  • CREATED
  • STARTED
  • RESUMED
  • DESTROYED

Lifecycle 위에 프래그먼트를 생성하면, Lifecycle-Aware 컴포넌트와 함께 생명주기를 다루는 데 사용되는 클래스들을 사용할 수 있게 됩니다. Lifecycle-Aware 컴포넌트는 프래그먼트의 활성, 비활성 상태를 자동으로 인식할 수 있습니다.

LifecycleObserver를 사용하는 대신에, 프래그먼트 클래스는 프래그먼트의 생명주기 변화에 상응하는 콜백 함수들을 포함하고 있습니다. onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()가 이에 해당됩니다.

프래그먼트의 뷰는 프래그먼트와 독립된 별도의 생명주기를 갖습니다. 프래그먼트는 뷰에 대한 LifecycleOwner를 유지하며, 이는 getViewLifecycleOwner() 또는 getViewLifecycleOwnerLiveData()로 접근할 수 있습니다.

프래그먼트 뷰에 대한 생명주기에 접근하는 것은, Lifecycle-Aware 컴포넌트가 프래그먼트의 뷰가 존재하는 동안에만 작업을 수행해야 하는 상황 (예: 화면에만 표시되는 LiveData 관찰)에 유용합니다.

이 포스팅에서는 프래그먼트 생명 주기에 대해 자세히 설명하고, 프래그먼트의 생명 주기 상태를 결정하는 몇 가지 규칙을 설명할 것입니다. 그리고 생명 주기 상태와 프래그먼트 생명 주기 콜백 간의 관계도 알아볼 것입니다.

Fragments and the fragment manager

프래그먼트가 초기화 되면, INITIALIZED 상태로 시작합니다. 프래그먼트 생명주기 내에서 다른 상태로 전환하기 위해, 프래그먼트는 반드시 FragmentManager에 추가되어야 합니다. FragmentManager는 프래그먼트의 상태를 결정하고 그 상태로 이동시킵니다.

프래그먼트 생명주기를 넘어서, FragmentManager는 프래그먼트를 호스트 액티비티에 연결하고 프래그먼트가 더 이상 사용되지 않을 때 분리하는 역할도 수행합니다. 이를 위해 프래그먼트 클래스는 onAttach(), onDetach() 라는 콜백 함수를 갖고 있으며, 개발자는 이러한 이벤트 중에 하나가 발생할 때 수행할 작업을 재정의할 수 있습니다.

onAttach() 콜백 함수는 프래그먼트가 FragmentManager에 추가되어 호스트 액티비티에 부착될 때 호출됩니다. 이 지점에서 프래그먼트가 활성화 되며, FragmentManager는 프래그먼트의 생명주기 상태를 관리하기 시작합니다. 그리고 findFragmentById()와 같은 FragmentManager 함수들로 프래그먼트 객체를 획득할 수 있습니다.

onAttach() 함수는 항상 생명주기 상태 변화가 있기 전에 호출됩니다.

onDetach() 콜백 함수는 프래그먼트가 FragmentManager로부터 삭제되어 호스트 액티비티로부터 분리될 때 호출됩니다. 프래그먼트는 비활성 상태로 전환되며, findFragmentById() 함수로 프래그먼트를 획득할 수 없습니다.

onDetach() 함수는 항상 생명주기 상태 변화 이후에 호출됩니다.

참고로, 이러한 콜백 함수들은 FragmentTransaction의 attach(), detach() 함수와는 무관합니다.

주의: FragmentManager에서 제거된 Fragment 인스턴스를 재사용하지 마십시오. 프래그먼트가 자신의 내부 상태를 정리하는 동안 실수로 자신의 상태를 재사용된 인스턴스로 전달할 수 있습니다.

Fragment lifecycle states and callbacks

프래그먼트의 생명주기 상태를 결정할 때, FragmentManager는 다음과 같은 것을 고려합니다.

  • 프래그먼트의 최대 상태는 FragmentManager에 의해 결정되므로, 프래그먼트는 FragmentManager의 상태를 넘어설 수 없습니다.
  • FragmentTransaction의 일부로 setMaxLifecycle()을 사용하여 프래그먼트에 최대 수명 주기 상태를 설정할 수 있습니다.
  • 프래그먼트의 생명 주기 상태는 부모보다 그 범위가 클 수 없습니다. 예를 들어 상위 프래그먼트나 액티비티는 하위 프래그먼트보다 먼저 시작되어야 합니다. 마찬가지로 하위 프래그먼트는 상위 프래그먼트나 액티비티 전에 중지되어야 합니다.

주의: <fragment> 태그를 사용하면 프래그먼트가 해당 FragmentManager의 상태를 넘어서 이동할 수 있으므로, XML에서 프래그먼트를 추가할 때 <fragment> 태그를 사용하지 마십시오. 대신 XML을 사용하여 프래그먼트를 추가하려면 항상 FragmentContainerView를 사용하십시오.

프래그먼트의 생명 주기가 진행됨에 따라 프래그먼트의 상태는 위아래로 이동합니다. 예를 들어, 백 스택의 맨 위에 push 된 프래그먼트는 CREATED → STARTED → RESUMED 처럼 위쪽으로 이동합니다. 반대로, 프래그먼트가 백 스택에서 pop 되면 RESUMED → STARTED → CREATED → DESTROYED 처럼 아래쪽으로 이동합니다.

Upward state transitions

Fragment CREATED

프래그먼트가 CREATED 상태에 도달하면, 프래그먼트는 FragmentManager에 추가되어 onAttach() 함수가 이미 호출된 상태입니다.

이 위치는 프래그먼트의 SavedStateRegistry를 통해 '프래그먼트 자체'와 관련된 모든 저장된 상태를 복원하기에 적절합니다. 현재 프래그먼트의 뷰가 생성되지 않았으므로 '프래그먼트의 뷰'와 관련된 모든 상태는 뷰가 생성된 후에만 복원해야 합니다.

이러한 상태 변화는 onCreate() 콜백을 호출합니다. 이 콜백에서 onSaveInstanceState()에 의해 저장된 이전 상태를 포함하는 savedInstanceState 번들 인자를 받습니다. 프래그먼트가 처음 생성될 때 savedInstanceState는 null이지만, 다음에 재생성될 때는 onSaveInstanceState()를 오버라이드 하지 않아도 항상 null이 아닙니다.

Fragment CREATED and View INITIALIZED

프래그먼트 뷰의 생명주기는 프래그먼트가 유효한 뷰 인스턴스를 제공할 때만 생성됩니다.

대부분의 경우, @LayoutId를 갖는 프래그먼트 생성자를 사용하여 onCreateView()를 재정의하지 않아도 적절한 시점에 자동으로 뷰를 인플레이트 할 수 있습니다. 또한 onCreateView()를 재정의하여 프래그먼트의 뷰를 프로그래밍 방식으로 인플레이트 하거나 생성할 수도 있습니다.

프래그먼트의 뷰가 null이 아닌 뷰로 인스턴스화 된 경우에만, 해당 뷰가 프래그먼트에 설정되며 getView()로 객체를 획득할 수 있습니다. 그런 다음 getViewLifecycleOwnerLiveData()프래그먼트의 뷰에 해당하는 새로 초기화된 LifecycleOwner로 업데이트 됩니다.

이때 onCreateView()에서 반환된 뷰 객체는 onViewCreated() 콜백 함수의 매개변수로 전달됩니다. onViewCreated()는 뷰의 초기 상태를 설정하고, 프래그먼트의 뷰를 업데이트하는 LiveData 인스턴스를 관찰하고, 프래그먼트의 뷰에 있는 RecyclerView 또는 ViewPager2 인스턴스에 어댑터를 설정하기에 적절한 시점입니다.

Fragment and View CREATED

프래그먼트의 뷰가 생성되면 이전 뷰 상태가 있는 경우 복원되고, 뷰의 생명주기가 CREATED 상태로 이동합니다. 또한 뷰의 LifecyclerOwner는 옵저버에게 ON_CREATE 이벤트를 발생시킵니다. 여기에서 프래그먼트의 뷰와 관련된 모든 추가적인 상태를 복원해야 합니다.

이 전환은 또한 onViewStateRestored() 콜백을 호출합니다.

Fragment and View STARTED

여기에서 Lifecycle-aware 컴포넌트를 프래그먼트의 STARTED 상태에 연결하는 것을 강력히 권장합니다. 왜냐하면, 이 시점은 프래그먼트 뷰가 생성된 경우 이용 가능하며, 프래그먼트의 하위 FragmentManager에서 FragmentTransaction을 수행하는 것이 안전하다고 보장되기 때문입니다. 프래그먼트 뷰가 null이 아니라면, 프래그먼트 뷰의 생명주기는 프래그먼트 생명주기가 STARTED 상태로 이동하자마자 STARTED 상태로 이동합니다.

프래그먼트가 STARTED 상태가 되면, onStart() 콜백 함수가 호출됩니다.

Fragment and View RESUMED

프래그먼트가 표시되면, 모든 애니메이터 및 트랜지션 효과가 완료된 것이며, 프래그먼트는 사용자 상호 작용하기 위한 준비가 완료된 것입니다. 이때 프래그먼트의 생명주기가 RESUMED 상태로 이동하고 onResume() 콜백이 호출됩니다.

RESUMED 상태로의 전환은 사용자가 이제 프래그먼트와 상호 작용할 수 있음을 나타내는 적절한 신호입니다. RESUMED 상태가 아닌 프래그먼트는, 뷰에 수동으로 포커스를 설정하거나 입력 함수의 visibility을 조절하려고 시도하면 안 됩니다.

Downward state transitions

Fragment and View STARTED

사용자가 프래그먼트를 떠나기 시작했지만 프래그먼트가 계속 표시되는 경우, 프래그먼트와 해당 뷰의 생명주기는 STARTED 상태로 돌아가며 해당 옵저버에게 ON_PAUSE 이벤트를 발생시킵니다. 프래그먼트는 이후 onPause() 콜백을 호출합니다.

Fragment and View CREATED

프래그먼트가 더 이상 표시되지 않으면 프래그먼트와 해당 뷰에 대한 생명주기가 CREATED 상태로 이동하고, 해당 옵저버에게 ON_STOP 이벤트를 발생시킵니다.

이 상태 전환은 상위 액티비티 또는 프래그먼트가 중지될 때 뿐만 아니라 상위 액티비티 또는 프래그먼트의 상태 저장에 의해서도 트리거 됩니다. 이 동작은 프래그먼트의 상태가 저장되기 '전에' ON_STOP 이벤트가 호출되도록 보장합니다. 따라서 ON_STOP 이벤트는 자식 FragmentManager에서 FragmentTransaction을 수행해도 안전한 마지막 시점이 됩니다.

위의 그림에서 볼 수 있듯이, onStop() 콜백 함수와 상태를 저장하는 onSaveInstanceState() 함수의 호출 순서는 API 레벨에 따라 다릅니다. API 28 이전의 모든 API 레벨의 경우, onStop() 전에 onSaveInstanceState()가 호출됩니다. API 레벨 28 이상에서는 호출 순서가 뒤바뀝니다.

Fragment CREATED and View DESTROYED

모든 종료 애니메이션과 트랜지션이 완료되고 프래그먼트의 뷰가 윈도우에서 분리되면, 프래그먼트 뷰의 생명주기가 DESTORYED 상태로 이동하고 해당 옵저버에게 ON_DESTROY 이벤트를 발생시킵니다. 그런 다음 프래그먼트는 onDestroyView() 콜백을 호출합니다. 이 시점에서 프래그먼트의 뷰는 생명주기가 끝나게 되고, getViewLifecycleOwnerLiveData()null을 반환합니다.

이 시점에서 프래그먼트의 뷰에 대한 모든 참조가 제거되어 프래그먼트의 뷰가 가비지 컬렉터에 의해 수집될 수 있어야 합니다.

Fragment DESTROYED

프래그먼트가 제거되거나 FragmentManager가 소멸되면, 프래그먼트의 생명주기가 DESTROYED 상태로 이동하고 해당 옵저버에게 ON_DESTRY 이벤트를 발생시킵니다. 그런 다음 프래그먼트는 onDestroy() 콜백을 호출합니다. 이 시점에서 프래그먼트는 생명주기의 끝에 도달한 것입니다.

참고자료

profile
습관이 될 때까지 📝

0개의 댓글