Activity Lifecycle

quokka·2022년 1월 8일
0

안드로이드 개념

목록 보기
1/2

Activity Lifecycle

앱이 비정상 종료되지 않고, 의도한 대로 동작하도록 하려면 lifecycle에 대한 이해가 필요하다. 사용자가 앱을 탐색거나 나갔다가 돌아오는 등 앱을 사용하는 과정에 lifecycle 콜백이 언제 실행되는지를 알아보자. 올바른 콜백 메서드에서 작업을 하고 적절하게 전환 처리를 해야 앱이 안정적으로 기능할 수 있다.

lifecycle을 고려하지 않았을 때 흔히 겪을 수 있는 문제는 다음과 같다.

  • 앱을 사용하는 도중 전화가 오거나 다른 앱을 이동할 때 사용하던 앱이 비정상 종료될 수 있다.
  • 시스템 리소스가 낭비될 수 있다.
  • 나갔다 들어왔는데 진행 상태가 저장되지 않아 처음부터 다시 시작해야 한다.
  • 화면 회전과 같은 구성 변경 시 비정상 종료되거나 입력한 데이터가 사라진다.

이러한 문제 발생을 예방하기 위해서는 lifecycle 콜백을 잘 구현해야 한다.

Activity lifecycle callbacks

액티비티 수명 주기의 콜백 메서드는 6가지가 있다.
onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy()

활성 상태 onCreate() → onStart() → onResume()

처음 실행된 액티비티는 onCreate() -> onStart() -> onResume()까지 호출한다. 그리고 setContentView()에서 출력한 내용이 화면에 나온다. onCreate()는 최초 한 번만 호출되고, onStart()onResume()은 반복적으로 호출할 수 있으므로 일반적으로 setContentView()onCreate()에서 호출한다.

onCreate()

  • 액티비티가 생성될 때 실행되는 콜백으로 필수적으로 구현해야 한다.
  • 액티비티가 생성되면 CREATED 상태가 된다.
  • 여기서는 이 액티비티의 수명 주기 동안 한 번만 발생하는 기본 어플리케이션 시작 로직을 실행한다.
  • 예를 들어 데이터를 바인딩하거나, 액티비티와 ViewModel을 연결할 수 있다.
  • 매개변수로 savedIsntanceState를 받는데, 이는 액티비티의 저장 상태가 포함된 Bundle 객체다. 처음 액티비티가 생성될 때는 null값이다.
  • lifecycle을 인식하는 구성요소들은 ON_CREATE 이벤트를 수신한다.

Android Developers 예제 코드

lateinit var textView: TextView

// some transient state for the activity instance
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // call the super class onCreate to complete the creation of activity like
    // the view hierarchy
    super.onCreate(savedInstanceState)

    // recovering the instance state
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // set the user interface layout for this activity
    // the layout file is defined in the project res/layout/main_activity.xml file
    setContentView(R.layout.main_activity)

    // initialize member TextView so we can manipulate it later
    textView = findViewById(R.id.text_view)
}

// This callback is called only when there is a saved instance that is previously saved by using
// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore
// other state here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// invoked when the activity may be temporarily destroyed, save the instance state here
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // call superclass to save any view hierarchy
    super.onSaveInstanceState(outState)
}

onStart()

  • STARTED 상태에 들어가면 onStart()가 호출되고 액티비티가 사용자에게 표시된다.
  • 사용자와의 상호작용을 준비한다.
  • 액티비티가 STARTED 상태가 되면 액티비티 lifecycle과 연결된 모든 컴포넌트는 ON_START 이벤트를 수신한다.
  • onStart() 메서드는 STARTED 상태에 머무는 것이 아니라 빠르게 완료되고, RESUMED 상태로 들어가 onResume()이 호출된다.
  • Broadcast Receiver는 여기서 등록한다.

onResume()

  • RESUMED 상태가 되면 포그라운드에 표시되고, onResume()이 호출된다.
  • 이제 사용자와 상호작용할 수 있다.
  • 앱에서 포커스가 떠날 때까지 이 상태에 머무른다.
  • 포커스를 떠나는 경우? ⇒ 다른 액티비티로 이동하거나, 기기 화면이 꺼지거나, 전화가 오는 등
  • 액티비티가 RESUMED 상태가 되면 액티비티 lifecycle과 연결된 모든 컴포넌트는 ON_RESUME 이벤트를 수신한다.
  • interruptive 이벤트가 발생하면 액티비티는 PAUSED 상태가 되고, on_Pause()가 호출된다.
  • PAUSED 상태에서 다시 RESUMED 상태로 돌아올 때 onResume()이 다시 호출된다.

onPause()

  • 액티비티가 화면에 보이지만 포커스를 잃어 이벤트를 처리할 수 없는 상태이다.
  • 액티비티가 항상 소멸되는 것은 아니지만 포그라운드에 있지 않게 되었을 때. 단 멀티 윈도우 모드에서는 화면에 여전히 표시 됨.
  • 멀티 윈도우 모드나 대화상자 같은 반투명 활동이 열려있을 때 액티비티가 부분적으로 보이지만 포커스를 잃은 상태가 일시중지된 상태. (참고로 액티비티에서 dialog를 띄운 상태는 일시 정시 상태가 아님)
  • 액티비티가 paused 상태가 되면 액티비티 lifecycle과 연결된 모든 컴포넌트는 ON_PAUSE 이벤트를 수신한다.
  • Paused 상태에서는 배터리 수명에 영향을 미칠 수 있는 모든 리소스를 해제할 수도 있는데 멀티 윈도우 모드에서는 여전히 화면에 보이는 상태일 수 있다. 그래서 멀티 윈도우 모드를 잘 지원하려면 onPause() 대신 onStop() 에서 해제하는 것이 좋다.
  • onPause()는 짧게 실행되므로 데이터를 저장하거나, 네트워크를 호출하거나, 데이터베이스 트랜잭션을 실행하면 안된다. 큰 종료 작업은 onStop() 상태에서 실행한다.
  • 액티비티가 다시 시작되면 onResume() 콜백을 호출한다.

onStop()

  • 액티비티가 사용자에게 더 이상 표시되지 않으면 Stopped 상태에 들어가고 onStop()이 호출된다.
  • 액티비티가 stopped 상태가 되면 액티비티 lifecycle과 연결된 모든 컴포넌트는 ON_STOP 이벤트를 수신한다.
  • 새롭게 시작된 액티비티가 화면 전체를 차지하거나 현재 액티비티 실행이 완료되어 종료될 때 onStop()이 호출된다.
  • 멀티 윈도우 모드에서 UI 관련 작업이 계속 진행된다.
  • CPU를 비교적 많이 소모하는 종료 작업을 여기서 실행한다. 예를 들어 데이터베이스에 저장하는 작업을 할 수 있다.
  • 액티비티가 다시 시작되면 onRestart()를 호출한다. onRestart() -> onStart() -> onResume()
  • 액티비티가 실행을 종료하면 onDestroy()가 호출된다.
  • Broadcast Receiver는 여기서 해제한다.

onDestroy()

  • 액티비티가 소멸되기 전에 호출된다.
  • 사용자가 액티비티를 완전히 닫거나 finish()가 호출되어 액티비티가 종료되는 경우
  • 기기 회전이나 멀티 윈도우 모드 등으로 인해 시스템이 일시적으로 액티비티를 소멸시키는 경우
  • 액티비티가 destroyed 상태가 되면 액티비티 lifecycle과 연결된 모든 컴포넌트는 ON_DESTROY 이벤트를 수신한다.
  • 액티비티 관련 뷰 데이터를 ViewmModel에 저장해 기기 회전 등의 이유로 destroyed 된 후에 액티비티가 다시 생성될 때 ViewModel을 보존해 액티비티 인스턴스에 전달한다.
  • 액티비티가 다시 생성되지 않을 경우 ViewModelonCleared()를 호출해 액티비티 소멸 전 데이터를 정리한다.

onSaveInstanceState()

  • lifecycle 콜백 메서드에 속하지는 않지만 중요하다.
  • onStop() 직전에 호출된다. (onPause()와 onStop() 사이에)
  • 액티비티가 종료되기 전에 데이터를 저장하는 코드를 작성한다. (프래그먼트에서도 마찬가지)

onRestoreInstanceState()

  • lifecycle 메서드 아님
  • onStart()와 onResume() 사이에 호출된다.
  • 화면 회전 등으로 액티비티가 강제 종료되고 다시 켜질 때 호출된다. 사용자가 뒤로가기 버튼을 누르거나 finish() 호출에 의해 액티비티가 종료되는 경우에는 호출되지 않는다. 화면 회전이나 메모리 부족 등으로 인해 시스템에 의해 강제 종료되는 경우에 호출된다.

화면 회전

[Main] onPause()
[Main] onSaveInstanceState()
[Main] onStop()
[Main] onDestroy()
[Main] onStart()
[Main] onRestoreInstanceState()
[Main] onResume()

홈 버튼 클릭

onPause() - onStop()

홈 이동 후 다시 돌아옴

onRestart() - onStart() - onResume()

MainActivity에서 DetailActivity를 호출하면?

[Main] onPause()
[Detail] onCreate()
[Detail] onStart()
[Detail] onResume()
[Main] onStop()

Detail에서 onResume()이 호출되어 포커스가 넘어가고 나서 Main의 onStop()이 호출된다.

DetailActivity에서 MainActivity로 돌아가면?

[Detail] onPause()
[Main] onRestart()
[Main] onStart()
[Main] onResume()
[Detail] onStop()
[Detail] onDestroy()

Main 화면이 완전히 표시되지 않는 onStop()까지 호출되었기 때문에 onRestart()가 호출된다. Main의 onResume()이 호출되어 포커스나 넘어간 후 Detail의 onStop()이 호출되고, 이어서 onDestroy()가 호출되어 소멸된다.

리소스 생성과 해제

기본적으로 리소스 생성과 해제는 대칭으로 한다.
onCreate()에서 생성했다면 onDestroy()에서 해제,
onStart()에서 생성했다면 onStop()에서 해제,
onResume()에서 생성했다면 onPause()에서 해제,


참고
Android Developers - The Activity Lifecycle

0개의 댓글