Activity
Activity는 안드로이드의 컴포넌트 중 하나로 사용자와 상호작용을 담당하는 단일화면으로 위 이미지와 같은 Lifecycle을 갖는다.
Activity의 생성부터 종료되기까지 일련의 모든 이벤트들에 대한 콜백을 지원해주기 때문에 상황에 맞는 로직을 구현할 수 있다.
이러한 이점을 통해 각 상태별로 리소스를 관리 포인트를 고려하여 메모리 누수에 대한 위험을 방지해야 한다.
Activity LifeCycle의 각 콜백에 대해 알아보자
onCreate() - 시스템이 Activity를 생성할때 실행하는 콜백으로 해당 Activity가 실행되면서 한 번만 실행해야 하는 로직들을 이곳에 구현하면 된다. 예를 들면 View 바인딩 작업이나 ViewModel을 연결하는 작업들이 이곳에서 이루어지면 된다.
또한 매개변수로 savedInstanceState가 주어지는데 이 변수는 Bundle의 객체로 이름에서 알 수 있듯이 간단한 UI 상태 데이터들을 저장할 수 있다. 물론 처음 시작하는 Activity라면 해당 객체는 null이다.
(PersistableBundle 이라는 매개변수도 받을 수 있는데, 이 매개변수를 넘겨주는 onCreate를 오버라이드 하면 Activity가 노출이 안된다. 직접 써보진 않았지만 해당 매개변수는 App ShortCut을 통해 intent 데이터 전달 시에 사용하는 것으로 보인다.)
onStart() - Activity가 시작되어 사용자에게 노출되고 포그라운드 작업으로서 사용자와 상호작용 가능한 상태 이전에 호출되는 콜백이다.
매우 빠르게 지나가는 상태이기에 부하가 큰 작업들을 하기엔 무리가 있다.
onResume() - Activity가 foreground에 전면 노출되고 사용자와 상호작용이 가능한 상태이다.
이 상태에서는 실행 가능한 모든 기능들을 활성화 할수 있고, 특별한 이벤트 혹은 인터럽트가 발생하지 않는 한 Resume 상태로 유지된다.
만약 슬립, 전화가 오는 등 이벤트가 발생한다면 Activity는 onPause() 상태로 변경되는데 해당 이벤트에 대한 처리가 끝나고 다시 Activity로 돌아올 경우 시스템은 다시 onResume()을 호출한다. 따라서 액티비티의 onResume 상태마다 매번 초기화가 필요한 작업을 수행하면 된다.
예를 들면 카메라를 초기화 하는 것이다.
이유는 다른 앱과 시스템 리소스 공유를 위해 onPause 상태에선 카메라를 메모리에서 제거해야 하기 때문이다.
때문에 onPause 이후 onResume이 될 경우 카메라가 메모리에 존재하지 않는 상태이기 때문에 다시 초기화하는 작업이 필요하다.
class CameraComponent : LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON\_RESUME)
fun initializeCamera() {
if (camera == null) {
getCamera()
}
}
@OnLifecycleEvent(Lifecycle.Event.ON\_PAUSE)
fun releaseCamera() {
if (camera != null) {
camera.release()
camera =
}
}
}
onPasue() - Activity가 포그라운드에 있지 않아 사용자와 상호작용할 수 없는 상태이다.
보통 다른 Activity나 전면 다이얼로그 노출로 인해 Activity가 가려진 상태로 다시 시작될 경우엔 onResume() 상태로 전환되지만 오랜 시간이 경과되고 다른 작업으로 인해 메모리가 부족하다고 판단될 경우엔 메모리 상에서 초기화될 수 있다.
onPause도 onStart와 마찬가지로 빠르게 지나가는 상태이기에 부하가 큰 작업은 자제해야 한다.
onStop() - 새로운 Activity가 실행되어 화면 전체에 노출되거나 Activity의 작업이 완료되어 종료되는 시점에 기존 Activity가 사용자에게 더 이상 보이지 않는 상태이다.
또한 액티비티의 객체는 메모리 안에 머무르는 상태인데 onPause와 마찬가지로 오랜 시간이 경과되고 다른 작업으로 인해 메모리가 부족하다고 판단될 경우엔 메모리 상에서 초기화 될 수 있다.
가급적이면 이 상태에서는 더 이상 필요하지 않은 리소스를 해제하거나 정리 해야한다.
onRestart() - Activity가 onStop() 이후로 재시작하는 상태이다 해당 콜백이 불리고 나서 onStart() 상태로 넘어간다.
onDestroy() - Activity가 완전한 종료가 된 상태이다. 보통 finish() 혹은 기기 회전을 통해 액티비티가 종료되는 경우에 호출된다.
만약 onStop()에서 까지 덜 해제된 리소스가 있으면 이 타이밍에서라도 처리해줘야 한다.
해제되지 않은 상태에서 종료가 되어버리면 메모리 누수가 발생할 수 있다.
Activity에서 다른 Activity가 노출되었을때 lifecycle 변화
D/BaseActivity: MainActivity onCreate
D/BaseActivity: MainActivity onStart
D/BaseActivity: MainActivity onResume
D/BaseActivity: MainActivity onPause
D/BaseActivity: SearchActivity onCreate
D/BaseActivity: SearchActivity onStart
D/BaseActivity: SearchActivity onResume
D/BaseActivity: MainActivity onStop
Fragment
Fragment는 Activity와 크게 다르지 않고 사용자와 상호작용을 담당하는 화면으로 위와 같은 Lifecycle을 가진다.
Fragment도 안드로이드 앱의 대표 컴포넌트에 끼워줄 법도 하지만 안드로이드 초창기에는 없던 개념이기도 하고 위에서 말했듯이 Activity의 단일 화면만으로는 많은 정보들을 표현하는데 한계가 있어 화면 분할 또는 분할된 콘텐츠 재사용을 위해 만들어진 요소이기 때문에 포함될 순 없다.
추가로 생각해보면 Fragment로만 앱을 실행할 수는 없으며, 흔히 말하는 4대 컴포넌트만이 안드로이드 앱의 엔트리 포인트가 될 수 있기 때문에 Fragment는 그저 Activity에 종속된 LifeCycle ViewGroup 정도로 볼 수 있다.
Fragment의 Lifecycle은 위에서 아래 방향으로 진행된다.
예를 들면 Fragment가 백 스택에 최상단으로 올라왔을 경우에는 생명주기가 CREATED - STARTED - RESUMED 순으로 진행되고, 반대로 백 스택에서 pop 됐을 경우에는 RESUMED - STARTED - CREATED - DESTROYED 순으로 진행된다.
Fragment LifeCycle의 각 콜백에 대해 알아보자
onAttach() - Fragment가 FragmentActivity의 FragmentManager에 추가되고, 호스트 Activity에 연결되었을 때 호출된다.
이 상태부터 Fragment가 활성화되고 FragmentManager에서 Fragment의 LifeCycle을 관리한다.
onCreate() - Activity의 OnCreate()처럼 초기 Fragment View 생성을 수행하지만 레이아웃과 관련된 작업을 하지는 않는다.
onCreateView() - Fragment의 View를 생성해서 리턴하는 역할을 한다. 이 시점에서는 View에 접근은 가능하지만 Fragment에 추가된 상태는 아니므로 View 바인딩 혹은 View를 생성하는 코드를 적용해야 한다.
이때 Fragment View의 라이프 사이클은 INITIALIZED 이다.
onViewCreated() - onCreateView에서 생성한 View가 인자로 전달되고
이 시점부터 View에 초기값을 설정해주거나 LiveData Observing, Pager/RecyclerView Adapter 초기화 작업을 해주는 게 적절하다.
onStart() - Fragment가 사용자에게 보이는 상태.
이 상태에선 Fragment와 View의 Lifecycle은 STARTED 이다.
onResume() - Fragment가 사용자와 상호작용이 가능한 상태.
이 상태에선 Fragment와 View의 Lifecycle은 RESUMED 이다.
onPause() - Fragment가 사라지고 있지만, 여전히 Visible 한 상태이다.
이 상태에선 Fragment와 View의 Lifecycle은 STARTED 이다.
onStop() - Fragment 가 더 이상 화면에 보이지 않게 되면 Fragment와 View의 Lifecycle 은 CREATED 상태가 되고, onStop() 콜백 함수가 호출되게 된다.
이 상태는 부모 액티비티나 프래그먼트가 중단됐을 때뿐만 아니라, 부모 액티비티나 프래그먼트의 상태가 저장될 때도 호출된다.
onStop()이 onSaveInstanceState() 함수보다 먼저 호출됨으로써 onStop()이 FragmentTransaction을 안전하게 수행할 수 있는 마지막 지점이 된다.
이때 Fragment View의 라이프 사이클은 CREATED 이다.
onDestroyView() - 모든 Animation과 Transition이 완료되고, Fragment에 표현된 View가 제거되는 단계이다.
Fragment 객체 자체는 사라지지 않고 메모리에 남아있기 때문에 메모리 누수를 방지하기 위해선 GC에 의해 제거될 수 있도록 Fragment View에 대한 모든 참조를 제거해야 한다.
onDestroy() - Fragment가 제거되거나 호스트 Activity가 Destroy 되었을 때의 상태이다.
이때 Fragment View의 라이프 사이클은 DESTROYED 이다.
이렇게 Activity와 Fragment에 대해서 알아보았고, 마지막으로 Activity에서 Fragment를 사용할 때 lifecycle의 변화를 확인해보고 마치자.
D/BaseActivity: onCreate
D/BaseActivity: onStart
D/BaseActivity: onResume
...
D/BaseFragment: onAttach()
D/BaseFragment: onCreate()
D/BaseFragment: onCreateView()
D/BaseFragment: onViewCreated()
D/BaseFragment: onStart()
D/BaseFragment: onResume()
...
'Android' 카테고리의 다른 글
[Android] RecyclerView 성능 최적화를 위한 ListAdapter 살펴보기 (0) | 2022.12.22 |
---|---|
[Android] Notification 커스텀하기 (0) | 2022.12.21 |
[Android] URI, URL (0) | 2022.11.24 |
[Android] Vector 이미지 (0) | 2022.11.24 |
[Android] left, top, right, bottom (0) | 2022.11.15 |