2011년 3월 11일 금요일

안드로이드 Activity 생명주기 (Activity Life Cycle )

1. Activity의 4가지 주요 상태 (4 essential states of Activity)

Active/Running 상태
Activity A가 화면의 가장 앞(foreground)에 있어 사용자가 직접 볼 수 있고, 포커스를 가지고 있는 상태.
다시 말하자면 입/출력이 가능한 상태.

Pause 상태
Active상태의 activity A가 화면의 foreground를 새로 점유한 activity N에게 포커스를 잃었지만 아직은 A의 일부가 보이는 상태 (foreground를 획득한 activity N이 화면 전체를 사용하지 않거나, 반투명하게 구현 되어 있을 때). 

Stop 상태
Active/Pause상태의 activity A가 full-screen크기의 activity N에게 화면 foreground를 선점 당한 상태.

Killed (Dead) 상태
Activity A가 생성되지도 않았거나 생성 후 소멸된 상태.


2. Activity의 상태 변이와 callback 메소드

Activity의 상태변이도

위에서 설명한 4가지 Activity상태간 변이 시에 코드의 흐름을 나타낸 그림이다. (클릭하면 크게 보임)


참고. onRestoreInstanceState(Bundle)onSaveInstanceState(Bundle)메소드들은 life cycle 에 직접적으로 관여하는 메소드는 아니며 상황에 따라 호출이 생략될 수 있다. 다음 단락: Activity의 강제 종료와 복구에서 자세히 설명.


위의 그림에서 파란색 실선은 정상적인 Actvity의 흐름이며 붉은색 점선은 비정상적인 Activity의 흐름이다.
위 그림을 이용하면 수 많은 Activity의 상태변이 case들에서 어떤 callback들이 어떤 차례로 호출되는지 쉽게 볼 수 있다.

예를 들어, Activity가 처음 실행돼서 사용자에게 사용되다 정상 종료 된다면 다음과 같은 callback이 차례로 호출된다.



또, Running상태의 Activity A가 다른 Activity B에게 완전히 가렸다 A가 다시 foreground로 와서 사용자에게 사용되는 경우는 다음과 같은 callback이 차례로 호출된다.



마지막 예로, 화면의 일부가 가린 pause 상태의 Activity A가 system 자원(메모리)의 부족으로 system에 의해 강제로 종료 당했다가 system 자원의 여유가 생겨 다시 복구 될 때는 다음과 같은 callback이 차례로 호출된다.




Life Cycle 관련 Callback 메소드 분석

Activity의 상태변이 시 호출되는 callback들을 각각 자세히 설명하면 다음과 같다. (클릭하면 크게 보임)


한가지 중요한 것은 위의 callback을 오버라이딩 할 때는 다음과 같이 super클래스의 원래 callback을 먼저 호출하여야 한다.
protected void onPause() {
super.onPause();
...
}





3. Activity의 강제 종료와 복구

System에 의한 Activity의 강제 종료

스마트폰 플랫폼은 PC와 달리 제한된 리소스(대표적으로RAM)을 가지고 있기 때문에 여러 가지 작업을 동시에 진행할 때 리소스 부족현상에 직면할 수 있다.

이는 심각한 문제를 유발 할 수도 있는데, 한가지 예를 들어 보자. 예를 들어 사용자가 이용하고 있는 게임 어플리케이션의 Activity A가 foreground서 사용자와 interact하고 있다고 치자. 이때 전화가 걸려오면 시스템은 incoming call Activity B를 foreground에 띄워 사용자에게 전화가 왔음을 알려야 한다. 하지만 만약에 A가 시스템의 리소스를 거의 전부 점유하고 있는 상황이라면 B Activity를 띄우는 것이 불가능 할 수 있다.

스마트폰에서 게임을 하는 것 보다 전화를 받는 Task가 훨씬 중요한 것이 일반적임으로, 이 경우 디바이스의 효율적인 운영이 이뤄진다고 볼 수 없고 이는 곧 user의 불편함으로 이어진다.

그래서 안드로이드에서는 여러 개의 Activity를 운영 중 시스템 리소스가 부족하면 특정 상태에 있는 Activity를 강제로 종료 할 수 있게 디자인 되어있다. Activity의 상태에 따른 강제 종료 우선 순위는 다음과 같다.
Running 상태: 절대 강제 종료 되지 않음
Pause 상태: 강제 종료 2순위
Stop 상태: 강제 종료 1 순위

전 단락의 life cycle 관련 callback 테이블을 보면 강제 종료 칼럼에 yes라고 표기된 onPause(), onStop(), onDestroy()가 있는데 이들 callback이 호출 된 뒤에는 Activity가 언제든지 강제 종료 될 수 있다는 뜻이다.

한가지 중요한 것은 onPause() callback이 실행 중에는 Activity는 아직 Running 상태이고 onPause()가 리턴 하자마자 Activity는 Pause상태가 되기 때문에 onPause() callback은 항상 return이 보장되는 반면 나머지 2 개의 callback, onStop(), onDestroy()이 실행 될 때는 Activity는 각각 Pause상태, Stop상태이기 때문에 return이 보장되지 않는다.

이런 이유(onPause() 이후에는 Activity가 강제 종료 당할 수 있음)로 onPause() callback에서 사용자가 진행하던 작업을 저장 하는 등의 강제 종료에 대비한 작업을 해주어야 한다.



강제 종료된 Activity의 복구

강제 종료된 Activity는 가동하는데 충분한 resource가 확보되면 (예를 들면 Activity A를 강제 종료 시켰던 Activity B의 종료 등) 자동으로 복구되지만, 한가지 작업이 이루어 지지 않는다면 사용자에게 심각한 불편을 초래할 수 있다. 다음과 같은 시나리오를 가정해 보자.


위와 같은 불편을 막기 위해, 안드로이드의 Activity 클래스는 onSaveInstanceState(Bundle) 메소드와 onRestoreInstanceState(Bundle) callback 메소드를 제공한다.

우선 위의 Activity 상태변이도에서 본것과 같이,
onSaveInstanceState(Bundle)은 onPause()전에 호출되며 파라미터로 전달 받는 Bundle 인스턴스에 현재 activity의 상태를 저장하게 된다. 저장된 Bundle인스턴스는 시스템이 Activity를 자동으로 복원할 때 호출되는 onCreate(Bundle) -> onStart() -> onRestroreInstanceState(Bundle) -> onResume() callback 중 onCreate(…)onRestoreInstanceState(…) callback에 모두 파라미터로 전달 됨으로 양쪽 어디서건 사용해서 강제종료 되기 전의 상태로 Activity를 복구 시키면 된다.

한가지 참고할 사상은 onSaveInstanceState(Bundle)과 onRestroreInstanceState(Bundle)은 life cycle과 직접적으로 관련이 있는 callback이 아님으로 Activity의 상태 변화 시 항상 호출된다는 보장이 없다. 논리적으로 꼭 필요한 상황에서만 호출됨으로 Activity상태가 바뀔 때 예외 없이 호출 되어야 하는 루틴은 life cycle 관련 callback (onResume(), onPause() 등)에서 구현 하여야 한다.

예를 들면, 사용자가 Activity 를 디바이스의 BACK key 로 직접 종료하거나 Activity.finish() 메소드를 사용해 정상 종료되는 경우에는 Activity의 현 상태를 복구할 필요가 없기 때문에 onSaveInstanceState(Bundle) callback의 호출은 생략된다.
User가 계산기 어플리케이션의 Activity A를 통해 시간이 오래 걸리는 작업(예, 숫자 100개 더하기 중 50개를 더한 상황) 중에 전화가 걸려왔는데 시스템의 리소스 부족으로 incoming call Activity B를 띄울 수 없는 상황이 발생 했다고 쳐보자. 시스템은 A를 강제 종료 시켜 부족한 리소스를 확보하고 B를 사용자에게 보여줘 사용자가 전화를 받을 수 있게 한다. 전화 통화를 완료한 후 시스템은 강제종료 된 A를 자동으로 복구 했지만 사용자가 이미 수행하고 있던 작업(100개중 50를 더한 중간 결과)의 상태는 초기화 되어 버리고 사용자는 다시 처음부터 작업을 수행해야 한다.
강제종료 -> onCreate(…) -> onStart() -> onRestoreInstanceState(...) -> onResume()
onSaveInstanceState(...) -> onPause() -> onStop() -> onRestart() -> onStart() ->onResume()
onCreate(Bundle) -> onStart() -> onResume() -> onPause() -> onStop() -> onDestory()

댓글 없음:

댓글 쓰기