본문 바로가기
Android 개발/android :: 공부

[Android Activity] 안드로이드 액티비티 생명 주기 (Life Cycle of Activity) 정리 및 이해

by 독학하는 1인 개발자 2020. 5. 12.

안드로이드 개발 공부

 

Andoird Activity

 

액티비티 생명(수명) 주기

 

정리 및 이해

 

Life Cycle of Activity

 

 

 

 

1. Activity 생명 주기란?

 

생명 주기?

안드로이드 폰을 써보면 누구나 알 수 있듯이

 

앱을 열면 앱에서 첫 화면이 뜨는데

그 안에서 또 새로운 화면을 열고 닫거나 할 수 있고

다시 앱을 끄거나

혹은 끄지 않고 다른 앱으로 전환할 수도 있다.

 

이러한 것이 생명 주기(Lifecycle)이다.

 

 

Activity 인스턴스

Activity는 하나의 화면이라고 생각하면 이해하기 쉽다.

 

개발자는 하나의 Activity 화면에 여러 기능을 구현할 수도 있고

혹은 각 기능마다 다른 Activity를 사용하여 화면을 전환시키며 진행할 수도 있다.

 

각각의 화면을 Activity 인스턴스라고 하는데

Activity 인스턴스는 생명 주기 안에서 상태가 계속 변한다.

 

- Activity를 생성하거나

- Activity를 잠시 중지하거나

- Activity를 다시 시작하거나

- Activity를 아예 종료하거나

 

이렇게 여러 상태 변화가 일어난다.

 

 

콜백

Activity 클래스는 각각의 상태변화를 알아차릴 수 있는 콜백을 제공한다.

쉽게 말하면 상태 변화에 따른 할일을 자동으로 알려주는 것이다.

 

개발자는 이 각각의 콜백에 대해

원하는 기능을 구현하여 넣을 수도 있다.

 

예를 들면

Activity가 처음 생성될 때는 onCreate() 메소드를 자동으로 콜백하는데

그 안에 변수 선언이나 데이터 베이스 불러오기 등등

원하는 기능을 구현하면,

Activity가 처음 실행될 때 onCreate()가 실행되면서 구현한 기능이 수행된다.

 

 

주의할 점

각각의 콜백에 대한 자세한 공부는 중요하다.

왜냐하면 잘 모를 경우에는 문제점이 발생할 수 있다.

 

- 사용자가 앱을 사용하는 도중 전화가 오거나 다른 앱으로 전환될 때 그에 맞는 콜백을 제대로 구현하지 않으면 앱이 비정상 종료될 수가 있다.

- 사용자가 앱을 비활성화했을 때 폰 시스템의 리소스, 메모리가 낭비될 수 있다.

- 사용자가 앱을 나갔다 들어올 때 진행중이던 상태나 작업 과정이 손실될 수 있다.

- 화면이 가로-세로로 전환될 때 비정상 종료나 진행 상태가 손실될 수 있다.

 

 

요즘 폰이 얼마나 잘나오는데 오류 나겠어? 라는 생각은 금물이다.

실제로 스토어에 앱을 출시하고 오류 보고를 검토하면

생각보다 memory 손실로 인한 오류가 많이 발생한다.

가벼운 앱에서도 말이다.

 

따라서 안정적인 앱을 개발하기 위해서는

특히 activity의 life cycle에 따른 메모리 관리를 꼼꼼하게 해주어야 한다.

메모리 관리에 대해서는 나중에 알아보고

여기서는 activity life cycle 부터 공부해보자.

 

 

 

 

2. Activity 생명 주기와 6가지 콜백 주기

 

주기 표

Activity 생명 주기 표를 보면,

대표적으로 6가지 콜백으로 정리할 수 있다.

 

onCreate(), onStart(), onResume()

onPause(), onStop(), onDestroy()

(구글 개발자 공식 사이트 제공 그림)

 

기본 주기

1) 처음 Activity를 실행하면 (Activity launched)

2) onCreate() -> onStart() -> onResume() 콜백 메소드를 호출하게 되고

3) Activity가 실행중인 모습이 사용자에게 보여진다. (Activity running)

 

4) 다른 Activity를 실행하게 되면 현재 Activity는 중지되어야 하므로 onPause() 콜백 메소드가 호출된다.

5) 사용자가 다시 Activity로 돌아오게 되면 onResume()이 호출되고,

6) 아니면 Activity가 더 이상 보이지 않는다면 onStop()이 호출된다.

 

7) onStop()이 호출된 이후 다시 Activity를 실행하려고 하면

8) onRestart()를 호출하면서 다시 onStart() 부터 호출해나간다.

 

9) 다른 앱을 실행하게 되어 onPause()나 onStop() 상태에서 메모리 문제로 앱을을 중단시켰을 때는

10) 다시 앱을 실행할 때 onCreate()를 호출하게 된다.

 

11) onStop() 상태에서 사용자나 시스템이 앱을 아예 종료하게 되면

12) onDestroy()가 호출되면서 Activity가 완전히 종료되고

13) 완전히 종료 후 다시 실행할 때는 onCreate() 부터 시작한다.

 

 

 

 

3. 6가지 콜백 메소드 정리

 

필수 구현: onCreate()

비필수 구현: onStart(), onResume(), onPause(), onStop(), onDestroy()

 

필수 구현은 구현하지 않으면 앱이 실행 자체가 되지 않고

비필수 구현은 구현하지 않아도 앱이 실행은 된다.

 

물론 onCreate()는 처음 Activity Class 생성시 자동으로 생성된다.

 

 

 

1) onCreate()

Activity 생성시

시스템이 Activity를 생성할 때 실행되는 것으로 '필수 구현'이다.

1
2
3
4
5
6
7
@Override
public void onCreate(Bundle savedInstanceState) {
    // call the super class onCreate to complete the creation of activity like
    // the view hierarchy
    super.onCreate(savedInstanceState);
 
}
cs

 

앱을 개발해보면 누구나 처음에 볼 수 있는 메소드다.

 

savedInstanceState

라는 매개변수를 받는데,

이는 Activity의 이전 저장 상태가 포함된 Bundle 객체로,

처음에는 이전 상태가 없으므로 당연히 null 값을 가진다.

 

if(savedInstanceState != null){} 정도의 코드를 작성해서

처음 실행이 아닐 때 원하는 기능을 구현할 수도 있다.

 

 

첫 화면 구성

보통은 setContentView()를 사용하여 첫 화면을 구현하고

TextView나 Button 등 xml 화면의 위젯들과 처음 연결하는 코드를 작성한다.

1
2
3
4
5
6
// xml 화면과 연결
setContentView(R.layout.main_activity);
 
// xml 화면의 텍스트뷰 
TextView textView = (TextView) findViewById(R.id.text_view);
 
cs

 

onCreate()는 전체 생명 주기에서 한 번만 호출되어야 한다. (앱이 kill된 상태에서는 재호출)

즉 맨 처음 시작할 때 수행하는 것이다.

 

 

onCreate() 메소드가 실행되면

activity는 시작된 상태가 되고

자동으로 연달아 onStart()와 onResum() 메소드가 호출된다.

 

 

 

 

2) onStart()

사용자에게 보이기 시작

onStart() 메소드가 호출되면 Activity가 이제 사용자에게 보이게 된다.

 

자동으로 호출되므로 직접 작성하지 않아도 앱은 돌아간다.

만약 나중에 onStart()가 호출될 때 원하는 작업이 있다면 @Override 해서 쓰면 된다.

1
2
3
4
5
@Override
protected void onStart() {
    super.onStart();
    // 원하는 코드 작성
}
cs

 

onCreate(), onStop() 이후 호출

생명 주기를 참고하면 onStop()이 호출된 이후 Activity를 다시 시작할 때는

onCreate()가 아닌 onStart() 부터 시작하므로

맨 처음 실행하는 onCreate()와는 다른 코드를 작성하고 싶을 때 용이하게 사용할 수 있다.

 

 

Observer 활용

하지만 구글 개발자 사이트에서는

onStart(), onResume(), onStop(), onPuase()를 직접 작성하여 코드를 넣는 것을 권장하지 않는다고 명시하고 있다.

대신에 LifecycleObserver를 사용하는 것을 권장하고 있다. (물론 직접 작성해서 쓰는 사람도 많다.)

사용법은 간단하다.

1
2
3
4
@OnLifecycleEvent(Lifecycle.Event.ON_START)
public void sampleMethod() {
 
}
cs

이렇게

@OnLifecycleEvent를 사용하여 원하는 콜백에 따른 메소드를 구현하면

LifecycleObserver가 해당 콜백이 일어날 때를 감지하여 메소드를 실행한다.

 

 

 

onStart() 메소드가 실행되고 나면 그 상태에 머무르지 않고

자동으로 onResume() 메소드가 호출된다.

 

 

 

3) onResume()

작동 재개

Activity가 재개된 상태를 시스템에 알려준다.

 

이 상태에서 이제 본격적으로 앱은 running 상태가 되어

사용자와 상호작용하게 된다.

사용자가 Activity를 본격적으로 사용하는 상태인 것이다.

 

반대로 말하면 Activity가 재개된 상태가 아니면 당연히 사용자는 그 Activity를 쓸 수 없는 것이다.

 

onStart() 처럼 자동으로 호출되므로 직접 작성하지 않아도 앱은 돌아간다.

만약 나중에 onResume()이 호출될 때 원하는 작업이 있다면 @override 해서 쓰면 된다.

1
2
3
4
5
@Override
protected void onResume() {
    super.onResume();
    // 원하는 코드 작성
}
cs

 

onStart(), onPause() 이후 호출

생명 주기를 참고하면 onPause()가 호출된 이후 Activity를 다시 시작할 때는

onResume() 부터 시작하므로

onCreate()나 onStart()와는 다른 코드를 작성하고 싶을 때 용이하게 사용할 수 있다.

 

예를 들어 onPause() 가 호출되어 일시 정지된 동안 해제시킨 것들을

onResume()에서 다시 초기화할 수 있다.

 

 

Observer 활용

구글 개발자 사이트의 예시를 참고하면

앞서 설명한 @OnLifecycleEvent를 사용하여

카메라를 사용하는 앱을 예시로 든 것인데

onResume()이 호출될 때

camera가 해제되었다면 다시 활성화시키는 코드이다.

1
2
3
4
5
6
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
public void initializeCamera() {
   if (camera == null) {
       getCamera();
   }
}
cs

 

 

리소스 해제

리소스는 해제와 할당 작업이 굉장히 중요하다.

리소스 관리를 제대로 하지 않을 경우

메모리 부족으로 앱이 비정상 종료될 수 있다.

 

onStart() 이후에 할당한 리소스들은

onStop() 이후에 해제.

 

onResume() 이후에 할당한 리소스들은

onPause() 이후에 해제.

 

 

 

 

 

 

4) onPause()

Activity 정지

사용자가 Activity를 떠날 때 첫 번째로 호출된다.

 

해당 Activity가 소멸되는 것은 아니다.

일시정지 상태로 볼 수 있다.

다른 Activity가 더 상위에 노출되거나

멀티 윈도우라면 여전히 보일 수도 있다.

 

Activity를 일시정지한 상태에서는

원활한 앱 이용을 위해 해당 Activity의 리소스를 해제시켜주는 것이 좋다.

메모리나 배터리에 영향을 미칠 수 있기 때문이다.

만약 멀티 윈도우처럼 여전히 보이는 상태라면

리소스 해제는 onPause() 대신 onStop()을 사용하는 것이 좋다.

 

 

Observer 활용

카메라 리소스를 해제하는 구글의 예시를 보자.

observer가 onPause()를 수신하여

카메라 리소스를 해제하는 코드이다.

1
2
3
4
5
6
7
@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void releaseCamera() {
    if (camera != null) {
        camera.release();
        camera = null;
    }
}
cs

참고로 != null 조건을 넣지 않아, null 상태에서 실행하게 되면

말 그대로 null은 없는 것이므로 실행이 불가하여 앱이 비정상 종료되는 경우가 많다.

그러므로 주의하자.

if(리소스명 != null){} 코드가 습관이 되어야 한다.

 

 

큰 작업은 onStop()에서

onPause()는 실행 순간이 짧으므로 

부하가 큰 종료 작업은 onStop()에서 하는 것이 좋다.

 

 

onPause() 상태에서 Activity가 다시 시작되면 onResume() 콜백을 호출하고,

Activity가 완전히 보이지 않게 되면 onStop()을 호출한다.

 

 

 

 

5) onStop()

Activity 중단

Activity가 완전히 사라지면 중단 상태가 되고 onStop() 콜백이 호출된다.

예를 들어 다른 Activity가 아예 전체를 차지하거나 Activity가 종료되는 시점이다.

 

onStop()에서는 주로 리소스 해제 코드를 작성한다.

예를 들어 애니메이션을 해제하거나 데이터베이스 저장 작업을 하면 된다.

 

 

Activity 종료

onStop()이 호출되어 Activity가 중단 상태가 되면 Activity 객체는 메모리 안에 머무르게 된다.

시스템은 자체적 관리를 통해 중단중인 Activity나 앱을 종료시킬 수 있는데

Lifecycle 표를 다시 참고해보면

onStop() 상태가 되면 시스템은 해당 Activity가 포함된 프로세스를 종료시킬 수 있다.

메모리가 더 필요할 경우에는 하나 더 올라가서 onPause() 상태에서도 프로세스를 종료하게 되는 것이다.

 

 

onStop() 상태에서 Activity가 다시 시작되면 onRestart() 콜백을 호출하고,

Activity가 실행을 종료하면 마지막으로 onDestroy()을 호출한다.

 

 

 

 

6) onDestroy()

Activity 소멸

Activity가 소멸되기 전에 호출된다.

 

- 사용자가 Activity를 완전히 닫거나 Activity에서 finish()를 호출한 경우.

- 구성 변경(화면 회전이나 멀티 화면)으로 일시적으로 ACtivity를 소멸시키는 경우.

 

onDestory()가 호출되면 Activity가 소멸되므로

소멸되기 전에 필요한 코드를 여기서 작성할 수 있다.

 

onDestry()로 Activity가 완전히 소멸된 후 (shut down)

다시 Activity를 실행하게 되면 (launched)

onCreate()부터 호출된다.

 

 

 

 

마지막으로

구체적으로 언제 각 콜백이 호출되는지 보고싶다면

다음과 같이 로그를 기록하여

앱 실행 후 이것저것 해보면서 그때그때 로그를 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Override
protected void onCreate(){
    super.onCreate();
    Log.d(TAG, "onCreate() 호출됨");
}
 
@Override
protected void onStart(){
    super.onStart();
    Log.d(TAG, "onStart() 호출됨");
}
 
@Override
protected void onResume(){
    super.onResume();
    Log.d(TAG, "onResume() 호출됨");
}
 
@Override
protected void onPause(){
    super.onPause();
    Log.d(TAG, "onPause() 호출됨");
}
 
@Override
protected void onStop(){
    super.onStop();
    Log.d(TAG, "onStop() 호출됨");
}
 
@Override
protected void onRestart(){
    super.onRestart();
    Log.d(TAG, "onRestart() 호출됨");
}
 
 
@Override
protected void onDestroy(){
    super.onDestroy();
    Log.d(TAG, "onDestroy() 호출됨");
}
 
cs

 

 

댓글