본문 바로가기
깡샘 코틀린

13-2 액티비티 생명주기

by 농농씨 2023. 7. 1.

액티비티의 상태

액티비티의 생명주기를 이해하고 각 상황에 적절하게 대처할 수 있어야 한다.

생명주기(life cycle)이란 액티비티가 생성되어 소멸하기까지의 과정을 말하며, Activity 클래스는 액티비티가 상태 변화를 알아차릴 수 있는 여러가지 콜백 함수를 제공한다. 이 콜백 함수에 액티비티의 상태가 바뀔 때마다 앱이 어떻게 동작해야 하는지를 구현한다.

액티비티의 상태는 다음처럼 크게 3가지로 구분할 수 있다.

  • 활성: 액티비티 화면이 출력되고 있고 사용자가 이벤트를 발생시킬 수 있는 상태
  • 일시 정지: 액티비티의 화면이 출력되고 있지만 사용자가 이벤트를 발생시킬 수 없는 상태
  • 비활성: 액티비티의 화면이 출력되고 있지 않는 상태

활성 상태

액티비티가 실행되어 화면에 나오고 사용자 이벤트를 처리할 수 있는 상태.

즉, 액티비티가 포커스를 가지는 상태. 버튼을 클릭하거나 에디트 텍스트에 글을 입력할 수 있음.

처음 실행된 액티비티는 onCreate() → onStart() → onResume() 함수까지 호출됨.

그리고 setContentView() 함수로 출력한 내용이 액티비티 화면에 나온다. 이것은 setContentView() 함수를 onCreate()나 onResume() 함수에서 호출해도 화면이 출력된다는 의미이다. 물론 onCreate() 함수는 최초에 한 번만 호출되고 onStart()나 onResume() 함수는 반복해서 호출할 수 있으므로, 일반적으로 setContentView()는 onResume() 함수에서 많이 호출한다.

 

일시 정지 상태

onPause() 함수까지 호출된 상태이며 일반적으로 액티비티가 화면에 보이지만 포커스를 잃어 사용자 이벤트를 처리할 수 없는 상태.

일시 정지 상태의 액티비티가 다시 포커스를 얻어 사용자 이벤트를 처리할 수 있으면 onResume() 함수가 자동으로 호출됨.

 

비활성 상태

액티비티가 종료되지 않고 화면에만 보이지 않는 상태.

인텐트로 다른 액티비티를 실행했거나 홈 버튼을 눌러 런처 화면으로 이동해 액티비티가 보이지 않는 상황. 안드로이드의 홈버튼은 런처 앱의 액티비티를 실행함. 홈 버튼을 누르면 화면에 보이던 액티비티가 종료된 게 아니라 단지 비활성 상태가 되는 것 뿐!

활성 상태에서 비활성 상태 되면 onPause() → onStop()  함수까지 호출됨.

그리고 다시 액티비티를 화면에 보이면 onRestart() → onStart() → →onResume() 함수까지 호출되어 활성상태 됨.

 

액티비티가 종료된다는 것은 Destroy()까지 호출되었다는 것을 의미함. ex. 사용자가 뒤로가기 버튼 눌러 액티비티 벗어나거나 코드에서 finish() 함수 호출한 상황. 두 상황 모두 안드로이드 11 버전까지는 onDestroy()까지 호출되어 액티비티가 종료되었으나, 안드로이드 12 버전(API 레벨 31)에서는 루트 액티비티가 아닐 때만 뒤로가기 버튼으로 액티비티가 종료됨.

 

루트 액티비티(root activity)란? 앱이 실행되었을 때 앱의 메모리 스택 맨 아래에 위치하는 액티비티.

만약 MainActivity를 가장 먼저 실행하고 MainActivity에서 DetailActivity를 실행했다 치면 앱 스택의 맨 아래에 MainActivity 쌓이고(root activity) 그 위에 DetailActivity 쌓임

이때 DetailActivity는 루트 액티비티가 아니므로 DetailActivity 화면에서 뒤로가기 버튼 누르면 onDestroy() 함수까지 호출되어 종료됨. 그런데 MainActivity()는 앱 스택의 맨 아래이므로 루트액티비티여서 뒤로가기 버튼 눌렀을 때 안드로이드 12 버전에서는 onDestroy()가 호출되지 않고 onStop()까지만 호출됨. 즉, 액티비티가 종료되지 않음

 

 

액티비티의 상태 저장

일반적으로 액티비티가 종료되면 객체가 소멸하므로 액티비티의 데이터는 모두 사라진다. 그리고 다시 그 액티비티를 실행하면 초기상태로 나온다. 그런데 액티비티가 종료될 때 유지해야 할 데이터를 저장했다가 다시 실행할 때 복원할 수 있다.

 

액티비티가 종료되는 상황 예시)코드에서 finish() 함수 호출, 루트가 아닌 액티비티에서 사용자가 폰의 뒤로가기 버튼 누르기, 화면에 오랫동안 안나와서 시스템이 알아서 종료시키기 등

이런 상황들은 액티비티를 다시 실행하더라도 어차피 초기 상태로 나와서 굳이 상태 저장했다가 복원할 필요는 X.

 

상태를 저장한다는 것은 액티비티가 종료되어 메모리의 데이터가 사라지더라도 다시 실행할 때 사용자가 저장한 데이터로 액티비티의 상태를 복원하겠다는 의미. ex. 화면회전할 때 액티비티 종료되었다가 나와서 액티비티의 데이터 초기화됨.

 

화면 회전할 때 여러 생명주기 함수가 어떤 순서로 호출되는지 알아보자.

onCreate()부터 onResume()까지 실행된 상태에서 화면을 회전하면 onPause()(표시멈추고) → onStop()(멈추고) → onSaveInstanceState()(저장하고) → onDestroy()(액티비티 종료)까지 호출되고 액티비티는 종료된다. 이때 액티비티에서 발생한 모든 데이터는 사라진다.

그리고 다시 액티비티 객체가 자동으로 생성되어 onCreate() → onStart() → onRestroeInstanceState() → onResume() 까지 호출되면서 화면에 액티비티가 출력된다.

 

만약 액티비티를 종료할 때 저장했다가 복원해야 할 데이터가 있다면 Bundle이라는 객체에 담아주면 된다. 다른 생명주기 함수는 매개변수를 가지지 않지만 onCreate(), onSaveInstanceState(), onRestoreInstanceState() 함수는 매개변수를 가지며 모두 Bundle 객체이다. 그러므로 이 번들 객체를 이용해 데이터를 저장하고 복원할 수 있다.

*Bundle이란? 여러가지의 타입의 값을 저장하는 Map 클래스.

// 번들 객체 사용
override fun onCreate(savedInstanceState: Bundle?) {
	super.onCreate(savedInstanceState)
}

override fun onRestoreInstanceState(savedInstanceState: Bundle) {
	super.onRestoreInstanceState(savedInstanceState)
}

override fun onsaveInstanceState(outState: Bundle) {
	super.onSaveInstanceState(outState)
}

onSavedInstanceState()는 onStop() 함수 다음에 호출되므로 이 함수가 호출된다는 것은 액티비티가 종료된다는 의미이다. 그러므로 개발자가 onSaveInstanceState() 함수의 매개변수로 전달되는 Bundle에 데이터를 담아 주면 자동으로 데이터를 파일로 저장해 준다.

 

// 번들에 데이터 저장
override fun onSaveInstanceState(outState: Bundle?) { // onSaveInstanceState 함수에 매개변수로 번들에 데이터 담음
    super.onSaveInstanceState(outState) 
    outState.putString("data1", "hello") // putString 함수로 번들에 데이터 저장함
    outState.putInt("data2", 10)
}

번들에 데이터 저장하려면 putString(), putInt() 등의 함수 이용. 그러면 자체 캐싱 파일에 데이터 저장해줌!

그리고 다시 액티비티가 생성되어 실행될 때 캐싱 파일이 있다면 그 내용 읽어서 번들 객체에 담아 onCreate(), onRestoreInstanceState() 함수의 매개변수로 전달해준다.

 

// 번들에 저장된 데이터 가져오기
override fun onRestoreInstanceState(saedInstanceState: Bundle) {
    super.onRestoreInstanceState(svaedInstanceState)
    val data1= savedInstanceState.getString("data1")
    val data2= savedInstanceState.getInt("data2")    
}

번들 객체에서 데이터 가져오려면 getString(), getInt() 등의 함수 이용함. 이처럼 onCreate(), onSaveInstanceState(), onRestoreInstanceState() 함수에 전달하는 번들 객체에 데이터를 담았다가 가져오면 액티비티가 종료되었다가 다시 실행될 때 액티비티의 데이터를 계속 유지할 수 있다.

 

❓화면 회전해도 에디트 텍스트에 입력했던 글은 그대로 남아있던데요?

❗️원래는 사라졌는데 지금은 개선돼서 안사라짐.

'깡샘 코틀린' 카테고리의 다른 글

13-4 태스크 관리  (0) 2023.07.01
13-3 액티비티 제어  (0) 2023.07.01
13-1 인텐트 이해하기  (0) 2023.06.30
12-4 확장된 플로팅 액션 버튼  (0) 2023.06.30
12-3 내비게이션 뷰 - 드로어 화면 구성  (0) 2023.06.30