면접 질문 목록으로 가기
면접 질문실전 질문꼬리 질문

Fragment 생명주기

skydovesJaewoong Eum (skydoves)||9분 소요

Fragment 생명주기

Fragment는 호스트 Activity의 생명주기와 밀접하게 연결되어 있으면서도 독립적인 자체 생명주기(lifecycle)를 갖습니다. Fragment는 생성, 뷰 생성, 가시성 확보, 인터랙티브 상태, 소멸이라는 단계를 거치며, 각 단계마다 전용 콜백이 제공됩니다. 특히 Fragment 자체의 생명주기와 Fragment 뷰의 생명주기가 분리되어 있다는 점은 안드로이드 개발에서 가장 오해가 많은 부분 중 하나이며, 면접에서도 자주 출제되는 핵심 주제입니다. 이 둘의 차이를 명확히 이해하지 못하면 메모리 누수나 크래시가 발생하기 쉬우므로, 반드시 정확하게 파악하고 계셔야 합니다.

이번 면접 질문을 통하여 아래 내용들을 학습하실 수 있습니다.

  • onAttach()부터 onDetach()까지 Fragment 생명주기 콜백의 전체 흐름을 추적할 수 있습니다.
  • Fragment 생명주기와 Fragment 뷰 생명주기의 차이를 명확하게 구분할 수 있습니다.
  • onDestroyView()에서 뷰 참조를 반드시 해제해야 하는 이유를 설명할 수 있습니다.
  • 데이터 초기화와 UI 초기화에 각각 적합한 콜백을 식별할 수 있습니다.
  • viewLifecycleOwner가 뷰 생명주기에 맞춰 관찰(observation)을 스코핑하는 원리를 설명할 수 있습니다.

연결(Attachment)과 생성

FragmentFragmentManager에 추가되면 가장 먼저 onAttach()가 호출됩니다. 이 시점에서 FragmentrequireActivity()를 통해 호스트 Activity에 대한 참조를 갖게 되며, ActivityContext에도 접근할 수 있습니다. 호스트와 상호작용할 수 있는 가장 이른 시점이 바로 여기입니다.

이어서 onCreate()가 호출되며, 여기서는 뷰 재생성(view recreation) 이후에도 유지되어야 하는 데이터를 초기화합니다. ViewModel 설정, Fragmentarguments Bundle로부터 인자 처리, 저장된 상태 복원 등이 이 콜백에서 이루어집니다. 뷰가 아직 존재하지 않으므로, 이 시점에서는 어떠한 뷰 관련 작업도 수행하면 안 됩니다.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    val userId = requireArguments().getString("user_id")
    viewModel.loadUser(userId) // ViewModel을 통한 데이터 로딩
}

Fragment 생성과 뷰 생성이 분리되어 있는 이유를 이해하는 것이 중요합니다. Fragment는 자신의 뷰보다 더 오래 살아남을 수 있기 때문입니다. Fragment가 백 스택(back stack)에 놓이면 시스템은 메모리를 확보하기 위해 뷰 계층을 소멸시키지만, Fragment 인스턴스 자체는 살려둡니다. Fragment의 ViewModel 역시 이 전환을 살아남아 메모리에 있는 모든 데이터를 유지합니다. 사용자가 다시 돌아오면 동일한 Fragment 인스턴스에서 onCreateView()가 재호출되며, ViewModel이 새 뷰를 채우는 데 필요한 데이터를 제공합니다. 면접에서 "왜 Fragment에서 뷰 생명주기가 별도로 존재하나요?"라는 질문이 나올 수 있으므로, 이 구조를 명확히 설명할 수 있어야 합니다.

뷰 생성과 인터랙션

onCreateView()Fragment의 레이아웃을 인플레이트하여 반환합니다. onViewCreated()는 그 직후에 호출되며, 뷰 바인딩, RecyclerView 어댑터 설정, ViewModel의 LiveDataFlow 관찰, 클릭 리스너 등록 등을 수행하는 표준적인 위치입니다.

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?,
    savedInstanceState: Bundle?
): View {
    return inflater.inflate(R.layout.fragment_user, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    // viewLifecycleOwner를 사용하여 뷰 생명주기에 맞춘 Flow 수집
    viewLifecycleOwner.lifecycleScope.launch {
        viewModel.userState.collect { state ->
            bindUserData(state)
        }
    }
}

생명주기 스코핑된 관찰에서 this(Fragment 자신) 대신 viewLifecycleOwner를 사용하는 것이 매우 중요합니다. Fragment의 생명주기는 뷰의 생명주기보다 길기 때문입니다. Fragment를 생명주기 소유자(lifecycle owner)로 사용하여 Flow를 수집하면, 뷰가 소멸된 이후(Fragment가 백 스택에 있을 때)에도 수집이 계속됩니다. 이 상태에서 수집기가 이미 존재하지 않는 뷰를 업데이트하려고 시도하면 크래시가 발생합니다. viewLifecycleOwner는 뷰 생명주기에 스코핑되어 있어, onDestroyView() 실행 시 자동으로 수집을 취소합니다.

이 면접 질문은 구독자 전용입니다

Dove Letter를 구독하시면 안드로이드, 코틀린 개발 관련 독점 면접 질문의 전체 내용을 볼 수 있습니다.

구독하기
면접 질문 목록으로 가기