[Android] 액티비티 (Activity) 와 프래그먼트 (Fragment) 의 생명 주기



 안드로이드의 생명 주기는 처음 안드로이드를 배울 때 자주 나오는 개념 중 하나입니다. 되게 간단한 것처럼 보이지만 막상 이것저것 파헤쳐보면 지엽적인 개념이 많이 나오기도 하고, 개발할 때 생명 주기 문제로 앱이 제대로 돌아가지 않는 문제도 발생하곤 합니다. 그렇기 때문에 한 번 정리해보는 것은 중요하다고 생각합니다. 한번 확인해 봅시다.



액티비티(Activity)의 생명주기

액티비티의 생명 주기에는 크게 6가지의 메서드가 존재합니다. onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy() 가 존재하는데요, (여기에 onRestart()가 포함됩니다.) 이들은 어느 시점에 호출되는지, 특징은 무엇인지 한 번 알아봅시다.





onCreate()

  • 액티비티를 선언할 때 필수적으로 구현해야 합니다. 
  • 액티비티가 생성될 때 맨처음에 한 번 호출됩니다. 이 때 생성됨 상태에 진입합니다.
  • 매개변수로 savedInstanceState라는 Bundle이 들어오는데, 이것은 상태를 저장하기 위한 번들이며 해당 번들에 값을 저장하고 onCreate 시에 다시 불러와서 이전 상태를 불러올 수 있습니다. Bundle인 만큼 너무 큰 데이터는 가져올 수 없습니다. (그래서 ViewModel 등으로 상태를 저장하곤 합니다.)
  • setContentView를 호출합니다. setContentView에 레이아웃 id를 넣어 해당 레이아웃을 액티비티의 메인뷰로 지정합니다.
  • 보통 초기화 관련 코드를 여기서 지정합니다.

onStart()

  • onCreate 이후에 호출됩니다.
  • 화면이 보여지기 시작될 때 호출됩니다.
  • 포그라운드에 표시될 준비를 하게 됩니다. 즉, 사용자와 상호 작용을 하기 전의 상태입니다. 

onResume()

  • onStart 이후에 호출됩니다.
  • 드디어 사용자와 상호작용을 하게 됩니다.
  • 상호 작용 도중에 특정 이벤트가 발생하면 onResume이 종료될 수 있습니다. 가령 전화가 오거나, 다른 액티비티로 넘어가거나, 화면이 꺼지는 등의 상태일 때 onResume이 종료됩니다.
  • 사용자와 직접적으로 상호작용하는 단계이므로 상호작용 동안 보여져야 할 모든 것들을 적어도 onResume이 호출될 때 처리해야 합니다.
  • 멀티 윈도우 같은 특별한 경우에는 화면에 보이긴해도 일시정지 상태 (onPause)일 수도 있는데, 멀티 윈도우에서 무조건 해당 액티비티가 포커스를 얻을 때만 특정 액션을 취하고 싶다면 onPause에서 해당 액션을 선언해야하고, 멀티 윈도우 상태에서도 해당 액션을 취하고 싶다면 onStart에서 액션을 선언해주어야 합니다. 그래야 onResume이 종료되고 onPause 상태에 돌입되어도 이미 onStart에서 액션을 선언했기 때문에 영향을 주지 않습니다.

onPause()

  • onResume 뒤에 호출됩니다. 정확히는 onResume 상태의 액티비티가 특정 이벤트로 상태 변경이 일어났을 때 호출됩니다.
  • 위에서 onResume이 포커스를 얻었을 때라고 한다면 당연히 onPause는 사용자로부터의 포커스를 잃었을 때 호출됩니다.
  • 아주 잠깐동안만 실행됩니다. 그래서 상태를 저장한다거나 데이터를 저장하는 작업을 onPause에서 실행하면 저장 도중에 끝날 수 있습니다. (네트워크 호출이라던지, db에 CRUD 한다던지 등등) 그러므로 이런 시간이 오래 걸릴 수 있는 작업은 onStop에서 해주셔야 합니다.
  • 사용자에게 완전히 보여지지 않을 때까지는 일시정지 된 상태를 유지하는데, 그래서 시스템도 어느 정도까지는 상태를 유지하고 있다가 onResume이 호출될 때 그 상태를 불러옵니다. 

onStop()

  • 사용자에게 완전히 보여지지 않게 되어버리면 onStop이 호출됩니다. 
  • 멀티 윈도우같이 조금만 보이는 형태가 아니라 완전히 화면이 새로운 액티비티 등으로 뒤덮여 버리면 onStop이 호출되는 것이라고 보면 됩니다.
  • 안 쓰는 리소스를 해제하거나 시간이 오래 걸릴 수 있는 작업을 진행합니다. 위에서 이야기했듯이 db 트랜잭션이나 네트워크 관련 작업, 또는 UI 관련 작업, 애니메이션 종료 같은 작업을 진행하면 됩니다.
  • onStop에서 분기하는 지점이 2가지가 있는데, 시스템에서 메모리 부족으로 프로세스를 중지하는 경우와, onStop 호출 뒤에 액티비티가 앞으로 다시 올 경우에 onRestart를 호출한 후 onStart를 부릅니다.

onDestroy()

  • 액티비티가 소멸되기 직전에 호출됩니다. 공식 문서에 의하면 아래의 경우에 호출됩니다.
    • (사용자가 활동을 완전히 닫거나 활동에서 finish가 호출되어) 활동이 종료되는 경우
    • 구성 변경(예: 기기 회전 또는 멀티 윈도우 모드)으로 인해 시스템이 일시적으로 활동을 소멸시키는 경우




프래그먼트(Fragment)의 생명주기

이번에는 프래그먼트입니다. 메서드가 좀 많은데, 크게 보면 액티비티의 생명주기와 그렇게 다르진 않습니다. 프래그먼트는 액티비티에 붙어서 돌아가니까요. 액티비티의 생명주기 내에서 동작하게 됩니다.



onCreate()

  • 액티비티와 크게 다르지 않습니다. 역시 초기화하는 부분이 여기에 들어가게 됩니다.

onCreateview()

  • 프래그먼트가 뷰를 그리기 위한, 즉 Layout을 Inflate하는 작업을 하는 부분입니다. 따라서 반환값도 View가 됩니다. 다만 UI를 그리지 않는다면 null을 반환하면 됩니다.

onViewCreated()

  • onCreateView에서 뷰를 그려놨으니, 해당 뷰와 관련된 여러 작업을 하기 적절한 위치입니다.
  • Recyclerview 작업이나 viewPager2 작업, LiveData를 옵저빙하는 등의 view의 초기값을 세팅하는 데 적절합니다.

onViewStateRestored()

  • view에 저장된 상태가 복원될 때 사용합니다. 
  • 가령 체크 표시나 토글 버튼 상태를 저장하게 됩니다.
  • MVVM에서는 ViewModel을 사용하다보니 크게 쓸 일이 없기도 합니다. 

onStart()

  • Fragment가 사용자에게 보여질 준비를 하는 단계입니다.
  • 프래그먼트 세팅은 됐고, FragmentManager에서 트랜잭션을 할 준비가 되어있습니다.
  • 사실 상 액티비티의 onStart와 거의 똑같습니다. 

onResume()

  • Fragment가 사용자와 상호작용하는 단계입니다.
  • 프래그먼트로 전환되는 애니메이션 효과 등이 완전히 끝나고 온전히 사용자에게 보여질 때 호출됩니다.
  • 그 외에는 액티비티와 비슷합니다.

onPause()

  • 역시 액티비티와 유사하게 일부 안 보이게 되거나 일시 중지되는, 포커스를 잃기 시작하는 단계입니다.
  • 재밌는 것은 onPause는 STARTED, 즉 '시작됨' 상태라는 점입니다. 프래그먼트의 생명주기에서는 '일시중지됨' 이라던가 '중지됨' 상태가 존재하지 않습니다. onDestroy가 호출되기 전까지 돌고 돈다는 이야기죠.

onStop()

  • 역시 사용자로부터 포커스를 완전히 잃었을 때 호출됩니다. 
  • 이 때는 '생성됨' 상태에 진입하게 됩니다.
  • 원래는 onStop 이전에 onSaveInstanceState가 호출되는데, 아래의 이미지처럼 API 28 이후부터는 순서가 역전되었습니다. 결과적으로 onStop의 프래그먼트 트랜잭션 작업이 안전하게 수행할 수 있게 되었다고 합니다.

 

onDestroyView()

  • 드디어 프래그먼트가 제거됩니다.
  • 프래그먼트가 제거되거나 FragmentManager가 소멸될 경우에 생명주기의 종료를 선언하는 역할을 하게 됩니다.
  • 이후 onDestroy를 호출하여 완전히 종료시킬 준비를 합니다.

onDestroy()

  • 사실 상 액티비티와 마찬가지의 역할을 합니다.




마치며..

결국 공식 문서나 다른 블로그에서 볼 수 있는 내용 그대로인데, 뭐 정리를 위한 것이니까요. 내용이 똑같아지는 것은 어쩔 수 없습니다.
사실 생명주기는 직접 로그를 찍어보면서 확인해보는 것이 좋다고 생각합니다. 화면 회전했을 때 onCreate부터 다시 시작되는 등의 케이스는 생각만 해서 나오기는 쉽지 않으니까요. 
역시 틀린 내용, 보충할 내용이 있으면 알려주세요. 피드백은 항상 환영합니다. 지금까지 읽어주셔서 감사합니다!


댓글