🐱🏍 Android Activity Life Cycle
안드로이드 액티비티 생명주기
액티비티의 생명주기를 알기 전에 간단히 액티비티는 무엇인가에 대해 알고 넘어 갈 필요가 있다.
먼저 위의 사진과 같이 안드로이드 어플리케이션은 기본적으로 4대 구성요소 (컴포넌트)로 구성되어 있다.
사진상으로 알 수 있듯이 각각 독립적인 형태로 존재 & 동작하면서 역할에 맞는 고유의 기능을 수행하게 되고,
Intent를 통해 서로 데이터를 주고받으며 통신한다.
이 중에서도 UI (= User Interface)와 가장 밀접한 관련을 가지고 있는것이 바로 Activity 단이며, 화면의 기본 구성단위가 된다.
즉, Android Application에 있어서 가장 기본이라고 할 수 있는 구성요소이고 대부분의 앱은 최소 한개 이상이 필수적이며 다수의 액티비티가 서로 연결된 형태로 구성되어있다고 볼 수 있다.
👀 액티비티 (Activity)
사용자에게 제공되는 UI가 있는 화면이다. 즉, 사용자와의 상호작용 (Interaction)을 담당하는 인터페이스이다.
* Activity의 주요 특징
- 모든 Activity Class에 대하여 AndroidManifest.xml 내부에 <activity> 선언이 있어야한다.
- Build가 성공적으로 이루어지려면 반드시 하나 이상의 Activity가 선언되어야 한다. (android.intent.action.MAIN)
- Activity 내 Fragment를 선언하면 화면 분할이 가능하다.
- 모든 Activity와 Service는 UI Thread (Main Thread)에서 동일한 Application Thread로 실행된다.
- 실행된 Activity (Activity Instance)는 Stack에 Push되고 onBackPressed된다면 Pop 된다.
- Activity의 생명주기에 따라 APP 또는 특정 Activity가 종료될 수 있다.
- Intent (인텐트)를 통해 다른 Activity를 호출할 수 있다.
* Fragment는 앱의 구성요소가 아닌가?
- Fragment는 Activity의 특징 일부를 물려받은 독자적인 생명주기를 가진 UI Component이다.
쉽게 말하면 Button, EditText 등과 같은 선상에 있는 개념이다.
그리하여 Fragment의 생명주기는 Activity가 활성화 된 상태 (실행중)에서 작동한다.
😎 액티비티 생명주기 (Activity Life Cycle)
위 다이어그램을 참고하여 생명주기 각각의 단계에서 어떤 작업을 하면 좋을까 ?
* onCreate( ) : 초기화 처리, View 생성 등 (Activity 만들어지는 상태, 액티비티 생성할 때)
- 콜백 메소드이며, Activity 생명주기의 생성 단계에서 최초로 Activity를 실행하면 처음으로 호출되는 함수.
- Activity가 생성될 때 Override하며, 화면을 정의하는 용도로 사용. (완료되면 onStart( )가 호출됨.)
- 초기화 관련 작업을 하면 좋다.
- 생성 단계인 onCreate( )에서 setContentView( )에 아래와 같은 형태로 Layout을 전달하여 화면을 정의.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
} // 여기서 R은 resource -> res -> r 에 해당한다.
// 즉 Resource/layout/activity_main.xml을 setContentView의 파라메터로 넘겨 화면을 정의한 것.
- 아래와 같은 파라메터를 수신하며, 이것은 Activity의 이전 상태를 저장한 Bundle 객체이다.
savedInstanceState: Bundle?
- Activity가 처음 생성 된 경우, savedInstanceState는 null 상태이다.
- 이 외에도 dataBinding( ), viewBinding( ), Instance화 등의 작업을 할 수 있다.
* onStart( ) : 통신, 센서 처리 시작 등 (화면에 나타나있는 상태로, 화면에 보여지기 시작할 때)
- 콜백 메소드이며, 이 시점부터 사용자가 Activity를 볼 수 있게 된다.
- 단, 아직 사용자와의 상호작용 (Interaction)은 불가능하다.
- ForeGround 상태에서 사용자와의 상호작용을 준비하는 단계이다.
- 최초로 Activity를 실행하면 onCreate( ) 다음으로 호출되는 함수이다.
- onStop( ) -> onRestart( ) 다음으로 호출되는 함수이기도 하다.
* onResume( ) : 필요한 애니메이션 실행 등 / 화면 갱신 처리 (화면에 나타나있는 상태로, 앱이 현재 실행중인 상태)
- 이 시점부터 Activity가 활성화 된 상태 (실행중인 상태)로 본다.
- 사용자와의 상호작용 (Interaction)이 가능한 단계로, Activity Stack의 TOP에 위치해있음
- 주로 Application의 코어 기능이 onResume( ) 에 설정됨.
- 사용자가 Activity에 대한 포커스가 없어질 때 까지 onResume( ) 상태가 지속됨.
- 포커스가 사라지면 Activity가 일시중지 상태가 되며, onPause( ) 가 호출됨.
- onPause( ) 상태에서 다시 Activity가 활성화 되면 onResume( ) 이 호출됨.
- onResume( ) 이 호출되면 Activity가 재개될 때 필요한 초기화 작업을 수행
- 최초로 Activity를 실행하면, onStart( ) 다음으로 호출되는 함수.
- onPause( ) 다음으로 호출되는 함수이기도 함.
* onPause( ) : 애니메이션 등 화면 갱신처리에 대하여 정지, 일시정지 할 때 필요없는 Resource를 해제하거나 필요한 데이터를 😎영속화함. (액티비티 화면의 일부가 다른 액티비티에 가려진 상태)
- Activity가 잠시 멈춘 단계.
- Activity의 동작이 Background에 위치하게 됨.
(멀티 윈도우 모드에서는 Activity가 백글가운드에 위치하게 되어도 화면에 보일 수는 있음.)
- 상황에 따라 onStop( ) 또는 onResume( ) 상태로 전환이 가능해짐.
- 만약 onResume( ) 이 호출 된 이후에 다른 Activity가 최상단에서 보여지는 경우 호출되는 함수.
(즉, 현재 Activity가 onResume( )에 의하여 활성화 되어 포커스를 가진 이후 현재 Activity가 포커스를 잃게되는 경우)
(ex : 전화가 왔거나, 다른 App을 잠시 실행시킨 경우)
- 만약 onPause( ) 가 호출 된 이후에 다시 기존 Activity로 돌아오는 경우 onResume( )이 호출 됨.
(즉, 다른 Activity가 Stack Top에서 보여진 이후 다시 기존 Activity로 돌아온 경우)
- 만약 다른 앱이 메모리를 필요로 할 경우 App Process가 종료될 수 있음.
- onPause( ) 단계에서 Activity가 Backgound에 있을 때 필요하지 않은 기능 (Resource)를 해제하는 동작을 할 수 있다.
- 일반적으로 onPause( )가 지속되는 시간이 짧다. (이벤트를 수행하기 전 끝나는 경우가 생김)
- 데이터 저장 또는 호출과 같은 Transaction은 사용하지 않는다.
- 실행 시간이 긴 이벤트는 onPause( )가 아니라 Activity가 멈춘 onStop( ) 메소드에서 사용하여야 한다.
* onStop( ) : 통신, 센서 처리 정지 등 (다른 Activity의 실행으로 화면이 완전히 가려진, 없어진 상태)
- Activity가 사용자에게 보이지 않는 단계로, onPause( ) 상태의 Activity가 이젠 완전히 중지되었을 때 호출 됨.
- 상황에 따라 onDestroy( ) 또는 onRestart( ) 상태로 전환이 가능해짐.
(만약 onResume( )이 호출 된 이후에 다른 Activity가 최상단에서 보여지는 포커스를 잃고, Activity가 완전히 보이지 않는 경우 호출되는 함수.)
(만약 onStop( )이 호출 된 이후 다시 기존 Activity로 돌아오는 경우 onStart( )가 호출 됨.)
- 사용자에 의한 경우 (onBackPressed( ) 호출 등) / 시스템에 의한 경우 (자원 부족 등) 에 의해 Activity가 완전히 종료되면 onDestroy( )가 호출 됨.
- 만약 다른 앱이 메모리를 필요로 할 경우 App Process가 종료될 수 있음.
- onStop( ) 메소드를 통해 Activity가 중지되었을 때 필요없는 Resource를 해제시키거나, 적절히 조정한다.
- onStop( ) 메소드에서는 부하가 큰 작업 (데이터 처리, 저장 관련 트랜잭션)을 하기에 적절하다.
* onRestart( ) : 보통 아무 작업을 안하긴 함.
- onStop( ) 상태였던 Activity가 재-시작 (Restart) 되는 단계
- onRestart( ) 뒤에는 onStart( ) 콜백이 자동 호출 됨.
* onDestroy( ) : 필요 없는 Resource는 해제 / Activity의 참조 정리 (Activity 종료. 즉, 앱 종료)
- Activity가 사용자에 의하거나 시스템에 의하여 완전 종료되는 경우에 호출되는 함수. (Activity 소멸 직전에 호출)
- 사용자에 의하여 종료 된 경우, onBackPressed( ) 호출 / finish( ) 등의 경우가 있음.
(* onBackPressed( ) 호출 시에는 기존 실행되었던 Activity가 onResume( ) 상태까지 Back 된 후 onDestroy( )가 호출 됨)
(* 화면 구성 변경으로 Activity가 소멸 된 경우 (화면 회전, 멀티 윈도우 모드로 변경 한 경우에도 호출))
- 시스템에 의하여 종료 된 경우, 대표적으로는 자원부족 문제를 해결하기 위한 메모리 확보의 경우가 있음.
- onDestroy( ) 단계에서 ViewModel 객체를 이요하면 Activity의 View Data를 보관할 수 있다.
- 화면 회전 등의 구성 변경으로 Activity가 종료 된 경우, 바로 새로운 Activity가 onCreate( ) 된다.
- Activity에 있는 Data를 더 이상 쓰지 않는다면 onDestroy( ) 단계에서 모두 정리 해 주어야 한다.
✍ 액티비티 생명주기에서의 메소드 호출 순서
(Method Call Sequence in Activity Life Cycle)
1. 앱 시작 : onCreate( ) ➡ onStart( ) ➡ onResume( )
2. 화면 회전할 때 : onPause( ) ➡ onStop( ) ➡ onDestroy( ) ➡ onCreate( ) ➡ onStart( ) ➡ onResume( )
3. 다른 액티비티가 TOP STACK될 때 / 전원 키로 화면 꺼질 때 / 홈 키 눌러서 이동할 때 : onPause( ) ➡ onStop( )
4. Back (뒤로가기) 키로 Activity 종료 : onPause( ) ➡ onStop( ) ➡ onDestroy( )
5. 다른 액티비티 상태에서 Back 키를 통해 기존의 Activity로 다시 돌아올 때 / 홈 키로 나갔다가 돌아올 때
onRestart( ) ➡ onStart( ) ➡ onResume( )6. 다이얼로그 액티비티 or 투명 액티비티가 화면에 뜰 때 : onPause( )
✍ 액티비티의 생명 주기의 라이프 타임
(Life-Time in Activity Life-Cycle)
* 전체 라이프 타임 : onCreate( ) ⏩ onDestroy( )
* 가시(Visible) 라이프 타임 : onStart( ) ⏩ onStop( )
* 포어그라운드 라이프 타임 : onResume( ) ⏩ onPause( )
=> 액티비티는 onPause( ) 이전까지 ForeGround이고, onPause( ) 까지 실행된다면 BackGround 상태가 된다.
=> 또한 onPause( )까지 화면 일부가 가시(Visible) 되고 onStop( ) 까지 실행되면 더 이상 Activity가 보이지 않는다.
=> onCreate( )에서 setContentView( )를 호출하지만 onCreate( ) ~ onResume( ) 까지는 하나의 메시지로 처리된다.
=> 따라서 onResume( ) 이후에 Activity가 시작된다.
😎 프래그먼트 생명주기 (Fragment Life Cycle)
Fragment는 Activity의 생명주기 아래에서 UI를 나타내는 용도로 독자적인 생명주기를 가지고 동작하기 때문에
안드로이드 4대 구성요소 중 Activity를 알았다면 Fragment는 필수적으로 함께 알아야 하는 부분이기 때문에 알아보자.
* onAttach( )
- Activity에서 Fragment를 추가하면 호출 됨. (Attach 상태)
- 인자(파라메터)로 Context를 받아서 Listener Interface를 Implement 한 경우에 Context를 통해 가져올 수 있음.
context : 맥락, 문맥
implement : 시행하다
* onCreate( )
- onAttach( ) 다음으로 호출되는 함수.
- Activity와 마찬가지로 초기화 해야하는 Resource들을 여기서 초기화 해 줌. (Activity에서의 onCreate( )와 비슷한 역할)
- 단, UI 관련 작업은 할 수 없음. (View와 ViewGroup의 UI binding과 같은 작업들)
- UI관련 작업 이외에 Int형 등등의 변수 초기화 등의 작업 정도는 가능. (프래그먼트를 생성하면서 넘겨준 값들이 있다면, 여기서 변수에 넣어주면 됨.
* onCreateView( )
- onCreate( ) 다음으로 호출되는 함수
- Layout을 Inflate하는 곳으로, View 객체를 얻을 수 있음.
- 따라서 현재 시점부터 Fragment에 속한 UI 관련 작업을 할 수 있는 단계
* onActivityCreated( )
- Fragment에서의 onCreateView를 마치고, Activity 에서의 onCreate( ) 다음으로 호출되는 함수
- Activity & Fragment의 View가 모두 생성 된 상태로, View를 변경하는 작업이 가능 한 단계.
* onStart( )
- onActivityCreated( ) 다음으로 호출되는 함수.
- Activity와 마찬가지로 이 시점부터는 사용자가 Activity를 볼 수 있음.
* onResume( )
- onStart( ) 다음으로 호출되는 함수.
- Activity와 마찬가지로 이 시점부터 Fragment가 활성화 된 상태 (실행중)으로 본다.
* onPause( )
- Fragment의 Host Activity가 포커스를 잃고 다른 Activity가 최상단 스택에서 보여지는 경우 호출 됨.
- 그러면 Fragment가 backStack 으로 들어감.
* onStop( )
- Fragment의 Host Activity가 포커스를 잃고 다른 Activity가 최상단 스택에서 보여지는 경우 이면서, 이제 Activity가 완전히 보이지 않아버리는 경우 호출됨.
* onDestroyView( )
- Fragment에 구현된 View가 제거되는 단계.
- 이 메소드가 호출된 이후 기존 Fragment가 BackStack에서 돌아오면 onCreateView( )가 호출됨.
* onDestroy( )
- Fragment를 완전히 제거하기 직전.
* onDetach( )
- Fragment가 제거되고, Activity로부터 해제될 때 호출됨 (Detach)
※ Fragment 추가 참고
- Activity의 onCreate( )기능을 Fragment에서는 두가지로 분리하였다. ( onCreate( ) / onCreateView( ) )
- Activity의 onDestroy( )기능 역시 Fragment에서는 두가지로 분리되었다. ( onDestroy( ) / onDestroyView( ) )
✍ 액티비티와 프래그먼트의 생명주기 동작 프로세스
(activity and fragment life cycle operation process)
액티비티와 프래그먼트의 콜백을 로그로 살펴보면 아래와 같다.
* New Fragment Commit ! (First) | * New Fragment Commit ! (Second) | * onBackPressed called ! |
Activity : onCreate( ) 호출 Activity : Fragment_1 commit( ) Fragment_1 : onAttach( ) Fragment_1 : onCreate( ) Fragment_1 : onCreateView( ) Fragment_1 : onActivityCreated( ) Fragment_1 : onStart( ) Activity : onStart( ) Activity : onResume( ) Fragment_1 : onResume( ) |
Activity : Fragment_2 commit( ) Fragment_2 : onAttach( ) Fragment_2 : onCreate( ) Fragment_1 : onPause( ) Fragment_1 : onStop( ) Fragment_1 : onDestroyView( ) Fragment_1 : onDestroy( ) Fragment_1 : onDetach( ) Fragment_2 : onCreateView( ) Fragment_2 : onActivityCreated( ) Fragment_2 : onStart( ) Fragment_2 : onResume( ) |
Fragment_2 : onPause( ) Activity : onPause( ) Fragment_2 : onStop( ) Activity : onStop( ) Fragment_2 : onDestroyView( ) Fragment_2 : onDestroy( ) Fragment_2 : onDetach( ) Activity : onDestroy( ) |
✍ 액티비티 전환 시 생명주기 메소드 호출
(Call Life-Cycle Method during Activity Transition)
아래 과정은 위의 경우와 반대로, 다른 Activity가 foreGround에서 다시 닫힐 때 기존의 Activity와의 동작 프로세스 과정이다.
✍ 생명주기 메소드 사용 관련 유의사항
* 리소스의 생성과 소멸은 대칭이 되는 생명주기 메소드에서 실행할 것.
예를 들어, onCreate( )에서 DB를 열었다면 onDestroy( )에서 닫아야 한다.
대칭 메소드 : onCreate ↔ onDestroy( ) / onResume( ) ↔ onPause( ) ↔ onStart( ) ↔ onStop( )
만약 onCreate( )에서 DB를 연 상태로 대칭이 아닌 onPause( )에서 DB를 닫게 되어버리면 오류가 발생할 수 있다.
예로, Activity_A에서 Activity_B로 전환하고, back 키를 눌러 Activity_A로 돌아왔을 때 onPause( ) 호출로 DB가 닫히긴 했지만, 다시 돌아왔을 때 onCreate( ) 호출이 되지 않아 DB가 열리지 않는 상황이 발생할 수 있다.
이와 같은 상황을 방지하기 위해 대칭이 되는 생명주기에서 리소스 생성, 소멸 관련 동작을 해야한다.
* 생명주기의 super 메소드를 호출할 때 주의 할 사항
onCreate( ), onStart( ), onResume( ) 메소드는 super 클래스의 해당 함수를 호출하고 작업해야 한다. (작업 전 사전 호출)
onPause( ), onStop( ), onDestroy( )는 작업을 하고 super 클래스의 해당 함수를 호출해야 한다. (작업 후 사후 호출)
추가적으로 생명주기 콜백 메소드들을 직접 호출하는 것은 추천하지 않는다. 만약 호출을 해야 한다면 별도의 메소드를 정의하여 해당메소드를 호출하는 것을 권장한다.
* 참고
https://developer.android.com/guide/components/activities/activity-lifecycle
https://velog.io/@eun3673/application-fundamentals-lifecycle
https://androman.tistory.com/58?category=745053
https://programmingfbf7290.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%95%A1%ED%8B%B0%EB%B9%84%ED%8B%B0Activity-%EC%83%9D%EB%AA%85%EC%A3%BC%EA%B8%B0-%EC%B4%9D%EC%A0%95%EB%A6%AC
https://brunch.co.kr/@mystoryg/80
https://bbaktaeho-95.tistory.com/62
'코딩 (독학) > ★ Kotlin' 카테고리의 다른 글
[Kotlin] KAPT Plugin (Room Database 적용 필수 라이브러리) (0) | 2022.04.05 |
---|---|
[Kotlin] 늦은 초기화 방법 (lateinit / lazy) (0) | 2022.04.05 |
[코틀린 문법] $를 사용한 문자열 템플릿 "${String}" (0) | 2022.03.24 |
[코틀린 문법] 코틀린에서의 함수 (Function in Kotlin) (0) | 2022.03.21 |
[코틀린 문법] 코틀린에서의 자료형 (Data type in Kotlin) (0) | 2022.03.21 |