어플 기능을 추가하면서 메모리 누수 문제로 고생을 좀 했다.
그냥 무심코 넘긴 Activity 생명주기가 얼마나 중요한지에 대해 새삼 알게되었다.
Activity 생명주기
안드로이드 생명주기(수명주기)란 Activity 의 상태정보가 변하는 것이다.
안드로이드 응용 프로그램은 PC용과 달리 화면이 작으므로 동시에 여러개의 Activity(화면)이 나올 수 없다.
화면 하나만 활성화된 상태이고, 나머지는 모두 비활성화된 상태로 남게 된다.
- 응용 프로그램이 시작되면 onCreate(), onStart(), onResume()가 차례로 수행되고, MainActivity 화면이 나온다.
홈 버튼을 눌러서 Activity를 백그라운드로 보내버리거나, NewActivity가 실행되어 화면 전환이 될 때
onPause() --> onStop() 이 두 메소드가 연달아 호출되며 백그라운드 스택으로 내려간다.
- New Activity 의 사용을 종료하면 onRestart(), onStart(), onResume()가 수행되고 다시 MainActivity 화면이 나온다.
- MainActivity 를 끝내면 아래 방향의 onPause(), onStop(), onDestroy()가 차례로 수행되고 응응 프로그램이 종료된다.
상태 메소드 |
설명 |
onCreate() |
- Activity 가 처음 만들어졌을 때 호출됨 - 화면에 보이는 뷰들의 일반적인 상태를 설정하는 부분 - 이전 상태가 저장되어 있는 경우에는 번들 객체를 참조하여 이전 상태 회복 가능 - 이 메소드 다음에는 항상 onStart() 메소드가 호출됨 |
onStart() |
- Activity가 화면에 보이기 바로 전에 호출됨 - Activity가 화면상에 보이면 이 메소드 다음에 onResume() 메소드가 호출됨 - Activity가 화면에서 가려지게 되면 이 메소드 다음에 onStop() 메소드가 호출됨 |
onResume() |
- Activity가 사용자와 상호작용하기 바로 전에 호출됨 |
onRestart() |
- Activity가 중지된 이후에 호출되는 메소드로 다시 시작하기 바로 전에 호출됨 - 이 메소드 다음에는 항상 onStart() 메소드가 호출됨 |
onPause() |
- 또다른 Activity를 시작하려고 할 때 호출됨 - 저장되지 않은 데이터를 저장소에 저장하거나 애니메이션 중인 작업을 중지하는 등의 기능을 수행하는 메소드임 - 이 메소드가 리턴하기 전에는 다음 Activity가 시작될 수 없으므로 이 작업은 매우 빨리 수행된 후 리턴되어야 함. - Activity가 이 상태에 들어가면 시스템은 Activity를 강제 종료할 수 있음 |
onStop() | - Activity가 사용자에게 더 이상 보이지 않을 때 소멸됨 |
onDestroy() | - Activity가 소멸되어 없어지기 전에 호출됨 - 이 메소드는 Activity가 받는 마지막 호출이 됨 - Activity가 애플리케이션에 의해 종료(finish)되거나 시스템이 강제로 종료시키는 경우에 호출될 수 있음. - 위의 두가지 경우를 구분할 때 isFinishing() 메소드를 이용함 - Activity가 이 상태에 들어가면 시스템은 Activity를 강제 종료할 수 있음. |
Activity stack 처리하는 방법
Activity를 그냥 intent생성해서 만들면 계속해서 새로 Activity를 start하고 스택으로 쌓이는 문제가 발생한다.
예를
들어서 A, B, C Activity를 A->B->C->A->C->B로 이동하고 뒤로가기를 누르면
다시 화면이 B->C->A->C->B->A 순으로 왔던 순서 반대로 나타난다.
문제점 검토
1. 뜨면 안될 화면도 뜨게 된다.(접근해선 안되는 이전화면으로 돌아가버린다)
2. 그냥 다시 뒤로가면 되는 화면인데 새로운 화면을 만들어서 그 위에 쌓아나간다.(이전 화면의 Activity를 새로 생성해서 위에 쌓는다)
해결방법
1. 접근해선 안되는 이전화면으로 돌아가버리는 문제
해당 Activity 의 JAVA 소스 파일에서 intent를 생성한 바로 다음에
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); //기존에 쌓여있던 스택을 모두 없앤다.
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // task를 새로 생성한다
를 추가해준다.
2. 이전 화면의 Activity로 돌아가야하는 문제
intent.addFlags(intent.FLAG_ACTIVITY_CLEAR_TOP); // 현재 Activity 없애고 이전 화면을 새로운 화면으로 지정
3. 어플 실행도중 전화가 왔을 때의 처리
onResume() 와 onPause() 에서 관련 코드 추가
@Override |
※ 참고로 Activity 생성시에 사용되는 Intent Flag 정리는 아래 블로그에 잘 정리되어 있다.
http://theeye.pe.kr/archives/1298
http://androidhuman.com/260 Activity 생애주기 샘플코드 및 설명
아래 사항은 여기에 추가하는 것이 적절한 거 같아서 콘솔 앱을 만들면서 적용한 걸 적어둔다. (Updated 2019.5.17)
서비스에서 Activity를 띄울 때는 인텐트에 플래그를 주어야 하며, 메인 Activity가 이미 메모리에 만들어져 있는 경우에는 메인 Activity의 onNewIntent() 메서드로 데이터가 전달된다.
@Override |
Intent intent = new Intent(Setting.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
FLAG_ACTIVITY_SINGLE_TOP 은 Activity를 재사용 하기 위해서, 필요없는 Activity를 제거하기 위해서 FLAG_ACTIVITY_CLEAR_TOP 을 같이 조합하였다.
이런경우 MainActivity 에서는 onNewIntent()를 override 해서 intent를 받아야 한다.
호출되는 순서는 onCreate() 대신에 onNewIntent()가 호출되고 다음으로 onResume() 이 호출된다.
처음 startActivity 호출시
1. onCreate → 2. onStart → 3. onResume
해당 Activity가 실행된 상태에서 FLAG를 추가하고 다시 startActivity 호출시
1. onNewIntent → 2. onResume
'안드로이드 > Android 기능' 카테고리의 다른 글
아파치 웹서버 vs nginx, 안드로이드 설계 고려사항 (0) | 2017.05.01 |
---|---|
안드로이드 KeyEvent.KEYCODE_BACK (0) | 2017.05.01 |
안드로이드 inflate (인스턴스화) (0) | 2017.04.08 |
버튼의 이벤트 처리 (0) | 2017.04.08 |
개념 잡는 Thread(쓰레드) 와 핸들러(Handler) (0) | 2017.04.02 |