앱이 비정상 종료되지 않고, 의도한 대로 동작하도록 하려면 lifecycle에 대한 이해가 필요하다. 사용자가 앱을 탐색거나 나갔다가 돌아오는 등 앱을 사용하는 과정에 lifecycle 콜백이 언제 실행되는지를 알아보자. 올바른 콜백 메서드에서 작업을 하고 적절하게 전환 처리를 해야 앱이 안정적으로 기능할 수 있다.
lifecycle을 고려하지 않았을 때 흔히 겪을 수 있는 문제는 다음과 같다.
이러한 문제 발생을 예방하기 위해서는 lifecycle 콜백을 잘 구현해야 한다.
액티비티 수명 주기의 콜백 메서드는 6가지가 있다.
onCreate()
, onStart()
, onResume()
, onPause()
, onStop()
, onDestroy()
처음 실행된 액티비티는 onCreate()
-> onStart()
-> onResume()
까지 호출한다. 그리고 setContentView()
에서 출력한 내용이 화면에 나온다. onCreate()
는 최초 한 번만 호출되고, onStart()
나 onResume()
은 반복적으로 호출할 수 있으므로 일반적으로 setContentView()
는 onCreate()
에서 호출한다.
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()
가 호출되고 액티비티가 사용자에게 표시된다. ON_START
이벤트를 수신한다.onStart()
메서드는 STARTED 상태에 머무는 것이 아니라 빠르게 완료되고, RESUMED 상태로 들어가 onResume()
이 호출된다.onResume()
이 호출된다. ON_RESUME
이벤트를 수신한다.on_Pause()
가 호출된다.onResume()
이 다시 호출된다.ON_PAUSE
이벤트를 수신한다.onPause()
대신 onStop()
에서 해제하는 것이 좋다.onPause()
는 짧게 실행되므로 데이터를 저장하거나, 네트워크를 호출하거나, 데이터베이스 트랜잭션을 실행하면 안된다. 큰 종료 작업은 onStop()
상태에서 실행한다.onResume()
콜백을 호출한다.onStop()
이 호출된다.ON_STOP
이벤트를 수신한다.onStop()
이 호출된다.onRestart()
를 호출한다. onRestart()
-> onStart()
-> onResume()
onDestroy()
가 호출된다.finish()
가 호출되어 액티비티가 종료되는 경우ON_DESTROY
이벤트를 수신한다.ViewmModel
에 저장해 기기 회전 등의 이유로 destroyed 된 후에 액티비티가 다시 생성될 때 ViewModel
을 보존해 액티비티 인스턴스에 전달한다.ViewModel
은 onCleared()
를 호출해 액티비티 소멸 전 데이터를 정리한다.[Main] onPause()
[Main] onSaveInstanceState()
[Main] onStop()
[Main] onDestroy()
[Main] onStart()
[Main] onRestoreInstanceState()
[Main] onResume()
onPause()
- onStop()
onRestart()
- onStart()
- onResume()
[Main] onPause()
[Detail] onCreate()
[Detail] onStart()
[Detail] onResume()
[Main] onStop()
Detail에서 onResume()이 호출되어 포커스가 넘어가고 나서 Main의 onStop()이 호출된다.
[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()
에서 해제,