본문 바로가기

안드로이드 Android

안드로이드 개발 (31) Activity Life Cycle

프로그래밍에서 주로 사용되는 생명주기(Life Cycle)은 프로그래밍 공학 쪽으로나 다양한 곳곳에서 사용되는 용어입니다.

Android 에서 말하는 LifeCycle은 주로 상황에 따라 생성 ~ 제거가 호출되는 전체 단계를 뜻합니다. Google Android는 LifeCycle에 맞게 콜백함수를 제공함으로써, Android 개발자가 특정 생명주기나 전체 생명주기를 이용해서 원하는 상황에 원하는 동작을 실행하도록 코드를 구현할 수 있습니다.

Android 에서 Life Cycle은 여러곳에 존재합니다. View, Service, BroadCastReceiver 등등 생성 ~ 제거 되는 순간에 따라 콜백함수를 커스텀 할 수 있습니다.

여러 Life Cycle 중에 실제 개발하면서 자주 신경쓰게 될 Activity LifeCycle에 대해 정리를 해보려 합니다.

1. Activity

액티비티는 앱에 반드시 최소 1개이상이 존재해야합니다. Manifest.xml에 Activity가 없는 앱은 실행할 수 없습니다.
그래서 기본적으로 App을 키자마자 Activity의 라이프 사이클부터 직면하게 됩니다.
Activity는 LifeCycle에 따른 크게 6가지의 콜백함수를 제공합니다.

onCreate()

- 시스템이 액티비티가 생성될 때 실행됩니다. Activity의 LifeCycle 에서 한 번만 발생해야 하는 시작 로직을 실행합니다. 콜백함수의 경우 onCreate(savedInstanceState: Bundle?) 매개 변수를 가집니다. 이번에 최초로 Activity가 생성이 됬다면 savedInstanceState는 null 입니다.

LifeCycle 동안 한번만 호출이 되는 함수이고 머무르지 않습니다.

class LifecycleComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun setData() { .... } ... }

(해당 Lifecycle를 인식하는 Componet를 사용한다면 이 component는 ON_CREATE 이벤트를 수신하고 @OnLifecycleEvent라는 주석이 있는 메서드가 호출이 됩니다.)

onStart()

- onCreate() 이후에 이어서 onStart() 가 호출이 됩니다.
onStart() 부터 사용자에게 Activity가 표시됩니다.
Activity를 Forground로 보내 사용자와 상호작용할 준비를 합니다.
onCreate()와 마찬가지로 머무르지 않고 다음 단계로 이동합니다.

class LifecycleComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) fun setData() { .... } ... }

(해당 Lifecycle를 인식하는 Componet를 사용한다면 이 component는 ON_START 이벤트를 수신하고 @OnLifecycleEvent라는 주석이 있는 메서드가 호출이 됩니다.)

onResume()

- onStart() 이후에 호출됩니다. 사용자가 본격적으로 앱과 상호작용할 수 있는 콜백함수 입니다.
onCreate()와 onStart()와 달리 이벤트가 발생 하지 않는다면 계속 onResume() 단계에서 머물게 됩니다.

onResume()를 방해하는 이벤트가 발생하면 onPause()가 발생하는데, onPause()에서
다시 onResume()으로 돌아갈 수 있습니다.

class LifecycleComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_RESUME) fun setData() { .... } ... }

(해당 Lifecycle를 인식하는 Componet를 사용한다면 이 component는
ON_RESUME 이벤트를 수신하고 @OnLifecycleEvent라는 주석이 있는 메서드가 호출이 됩니다.)

onPause()

- 해당 Activity가 forground Process 를 떠나있을때 첫번째로 호출이 됩니다.
(하지만 상황에 따라 Activity가 여전히 사용자에게 보이는 경우가 있습니다.)

Activity가 화면의 일부분으로 표시되면서 포커스를 잃는 경우에는
다음 단계로 가지 않고 onPause() 상태에서 머뭅니다. (대표적인 예: 멀티윈도우에서 포커스를 잃었을 때)

상황에 따라 Activity가 일부분으로 표시되는 경우가 있기 때문에,
UI 관련 리소스와 작업을 완전히 해제하거나 조정할 때는 onPause()를 사용하지 않는것이 좋습니다.

반대로 Activity가 아예 화면이 표시가 되지않을때 머무르지 않고 다음 단계로 넘어갑니다.

class LifecycleComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE) fun setData() { .... } ... }

(해당 Lifecycle를 인식하는 Componet를 사용한다면 이 component는
ON_PAUSE 이벤트를 수신하고 @OnLifecycleEvent라는 주석이 있는 메서드가 호출이 됩니다.)


onStop()

- 기존 Activity가 아예 화면에서 완전히 벗어난다면 onStop() 이 호출이 됩니다.
(Process Lifecycle 기준으로 background process 일때)

메서드에서 앱이 사용자에게 보이지 않는 동안 앱은 필요하지 않은 리소스를 해제하거나 조정하거나
CPU를 비교적 많이 소모하는 종료 작업을 실행해야 합니다.

그리고 Activity 객체가 메모리안에 머물게 됩니다.
또한 시스템은 레이아웃에 있는 각 View 객체의 현재 상태도 기록합니다.
그래서 사용자가 홈버튼으로 화면을 벗어놨다가 TASK를 통해 화면으로 돌아와도 UI 데이터들이 그대로 남아있습니다.

*하지만 OS 가 메모리가 부족하다면 해당 프로세스 자체를 해제시킬 수 있습니다.
bundle로 저장한게 있다면 onCreate()에서 bundle를 이용해서 기존 값들로 다시 불러올수 있습니다.

class LifecycleComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_STOP) fun setData() { .... } ... }

(해당 Lifecycle를 인식하는 Componet를 사용한다면 이 component는
ON_STOP 이벤트를 수신하고 @OnLifecycleEvent라는 주석이 있는 메서드가 호출이 됩니다.)


onDestory()

- onDestory()는 Activity가 소멸되기 직전에 호출됩니다.
아래 2가지 경우로 onDestory()가 호출됩니다.
Activity가 종료되는 경우,
구성 변경으로 인해 시스템이 일시적으로 Activity를 소멸 시키는 경우 (ex: 화면 회전)

Activity의 마지막 Lifecycle 입니다.
이전 콜백에서 처리하지 않은 리소스 해제가 있다면 onDestory()에서 마저 처리를 하기도 합니다.

class LifecycleComponent : LifecycleObserver { ... @OnLifecycleEvent(Lifecycle.Event.ON_DESTORY) fun setData() { .... } ... }

(해당 Lifecycle를 인식하는 Componet를 사용한다면 이 component는
ON_DESTORY 이벤트를 수신하고 @OnLifecycleEvent라는 주석이 있는 메서드가 호출이 됩니다.)

2. 다시 호출 될 수 있는 Activity LifeCycle 콜백함수

CREATE ~ DESTORY 까지 상황에 따라 단계별로 움직입니다.
이미 단계를 지났어도 상황에 따라 다시 호출 되는 콜백 함수가 존재합니다.

1) onPause ->onResume
- onPause 상황에서 일부 액티비티가 보이는 상황에서 일부였던 액티비티가 포커스를 찾았을 때 다시
onResume을 호출합니다.

2) onStop -> onRestart -> onStart
- 유저의 액션에따라 해당 액티비티가 화면에서 벗어놨다가 다시 해당 화면을 불러왔을 때 onRestart라는 함수가 호출 됩니다. 다시 onStart가 호출됩니다.

3) onStop -> onCreate
- onStop 일때, Android 의 메모리 부족으로 앱의 프로세스를 소멸한 상황에서
유저에 의해 해당 액티비티를 불러온다면 onCreate 부터 호출 됩니다. (프로세스를 소멸 시켯을뿐 액티비티는 그대로 남아있습니다.) onStop 에서 onSaveInstanceState()를 통해 bundle의 data를 저장했다면 onCreate에서 다시 소멸 되기전 data를 불러올 수 있습니다.

3. Activity 이동간의 LifeCycle 확인

1) 액티비티 첫 실행 main

첫 실행시 onCreate, onStart , onResume 순서대로 호출이 되고 onResume()에서 머문다는 것을 알 수가 있습니다.

2) 액티비티 이동 main -> second

-MainActivity가 포커스를 잃는 순간 onPause() 를 호출 합니다.
-SeocondActivity 가 onResume()호출 되고 나서야 MainActivity의 onStop()이 호출 됩니다.
-onStop 이후에 onSaveInstanceState() 호출 됩니다.

위의 경우 main -> secondActivity를 startActivity()로 이동했기 때문에
main이 backStack에 쌓여서 onDestory는 호출되지 않습니다.

3) 액티비티 뒤로가기 main <- second

뒤로가기 버튼을 눌러서 main으로 돌아갔을 때의 LifeCycle 입니다.
- Second의 onPause()
- main의 onRestart() -> onStart() -> onResume()
- Second의 onStop() -> onDestory()

onStop에 있는 main을 다시 불러와서 onRestart가 호출이 되는것을 볼 수 있습니다.
그리고 뒤로가기 버튼을 눌러서 Second의 메모리를 저장하지 않음으로 onSaveInstanceState()를 호출하지 않습니다.
그리고 onDestory()를 호출합니다.

4) second에서 task 창에서 activity 강제 종료

secondActivity을 보고 있는 상황에서 안드로이드 App의 Task 창에서 어플을 강제 종료했을 때 백스택에 담겻던 MainActivity까지 onDestory()가 호출이 되는 것을 알 수 있습니다.

4. Activity LifeCycle 과 프로세스

Android System 은 절대 Activity를 직접적으로 종료하지 않습니다. 다만, 메모리가 부족해지는 경우에 Activity 를 실행하는 Process를 종료함으로써 메모리를 확보하는 경우가 있습니다. 아래는 시스템이 Process를 종료할 가능성을 나타내는 표 입니다.

STOP ~ DESTORY 가 가장 프로세스가 종료될 가능성이 커집니다. 이에 대비해서 onSaveInstanceState(), ViewModel, 로컬 DB 등등을 통해서 프로세스가 종료됬을 때의 보존할 데이터들을 다시 불러올 수 있도록 준비해야합니다.

이상 Activity의 LifeCycle에 대해 알아봤습니다.