모바일 앱의 수명 주기는 앱이 실행, 최소화, 백그라운드에서 복귀 및 종료될 때의 동작 방식을 결정합니다. 이 기사에서는 App Lifecycle(iOS), Activity Lifecycle(Android), Fragment Lifecycle, ViewController Lifecycle 및 LifecycleOwner에 대해 다룹니다. 이러한 프로세스를 이해하는 것은 메모리 누수, 데이터 손실 및 앱의 잘못된 동작을 방지하는 데 매우 중요합니다. 자세한 내용은 공식 Android Activity Lifecycle 문서를 참조하세요.
주요 요점
개별 화면의 수명 주기를 살펴보기 전에 전체 앱의 수명 주기를 이해하는 것이 중요합니다. iOS에서 앱은 5가지 상태를 거칩니다: Not Running(실행 중 아님), Inactive(백그라운드, 이벤트 수신 안 함), Active(활성), Background(백그라운드, 코드 실행 중), Suspended(백그라운드, 코드 일시 중지됨). 이러한 상태는 AppDelegate에서 applicationDidFinishLaunching, applicationDidBecomeActive, applicationWillResignActive, applicationDidEnterBackground 및 applicationWillTerminate 메서드를 통해 관리됩니다.
Android에서 이에 해당하는 것은 Application Lifecycle이며, Application.ActivityLifecycleCallbacks 인터페이스를 통해 추적됩니다. 그러나 Android는 Activity(개별 앱 화면)의 수명 주기에 더 중점을 둡니다. 이는 Android 앱이 여러 Activities로 구성될 수 있고 각각 고유한 주기를 가지고 있기 때문입니다.
Android의 현대적인 접근 방식은 lifecycle-process 라이브러리의 ProcessLifecycleOwner를 사용하는 것입니다. 특정 Activity에 바인딩되지 않고 전체 프로세스의 상태를 추적할 수 있습니다. iOS에서는 UISceneDelegate(iOS 13부터) 또는 AppDelegate를 사용하여 앱 상태를 추적합니다. SceneDelegate는 iPad에서 여러 창(멀티윈도우)을 처리합니다. App Lifecycle을 이해하는 것은 백그라운드 동기화, 스트리밍 및 VoIP 통화가 포함된 앱을 개발할 때 IT Sectr에게 특히 중요합니다.
Activity는 Android 앱의 기본 구성 요소로, 하나의 화면을 나타냅니다. Activity는 사용자 작업 및 시스템 이벤트(화면 회전, 수신 전화, 메모리 부족)에 응답하여 운영 체제가 관리하는 명확하게 정의된 수명 주기를 가지고 있습니다.
| 메서드 | 설명 | 수행할 작업 |
|---|---|---|
| onCreate | Activity 생성 시 한 번 호출됨 | UI 초기화, findViewById, ViewModel 설정 |
| onStart | Activity가 표시됨 | 애니메이션 시작, BroadCastReceiver 등록 |
| onResume | Activity가 입력 포커스를 얻음 | 카메라, 센서, 애니메이션 시작 |
| onPause | Activity가 포커스를 잃음(부분적으로 표시됨) | 초안 저장, 애니메이션 중지 |
| onStop | Activity가 표시되지 않음 | 리소스 해제, 업데이트 중지 |
| onDestroy | Activity가 소멸됨 | 모든 참조 정리, LiveData 구독 취소 |
| onRestart | onStop 후 onStart 전에 호출됨 | 다시 초기화 |
중요: 임시 상태를 저장하기 위해 onSaveInstanceState가 onStop 전에 호출됩니다. 복원은 onCreate의 Bundle savedInstanceState 또는 ViewModel의 SavedStateHandle을 통해 이루어집니다. 수명 주기를 적절히 처리하지 않으면 화면 회전 시 앱이 저장되지 않은 모든 데이터를 잃게 됩니다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString("draft", draftText)
}
override fun onDestroy() {
super.onDestroy()
// Отписка от всех подписок
}
}
Jetpack Compose에서 Activity 수명 주기는 변경되지 않지만, Compose는 추가 도구를 제공합니다: LifecycleOwner를 통한 수명 주기 인식 컴포지션, 소멸 시 자동 리소스 정리를 위한 LifecycleEventEffect 및 DisposableEffect.
Android의 Fragment는 Activity 내에 존재하며 자체 수명 주기를 가지고 있습니다. 이는 Activity와 부분적으로 겹치지만 새 메서드를 추가합니다. Fragment는 Activity를 소멸시키지 않고 추가, 교체, 제거할 수 있어 더 유연하지만 더 복잡하기도 합니다.
Fragment Lifecycle의 주요 메서드: onAttach — Fragment가 Activity에 연결됨(첫 번째 호출); onCreate — 데이터 초기화; onCreateView — View 생성; onViewCreated — View 생성됨, UI 구성 가능; onStart — Fragment 표시; onResume — Fragment 포커스 있음; onPause — Fragment 포커스 잃음; onStop — Fragment 표시 안 됨; onDestroyView — View 소멸; onDestroy — Fragment 소멸; onDetach — Fragment가 Activity에서 분리됨.
Activity와의 주요 차이점: onCreateView와 onDestroyView는 여러 번 호출될 수 있지만(TabLayout 전환 시 등), onCreate는 한 번만 호출됩니다. 따라서 View 초기화는 onCreateView가 아닌 onViewCreated에서 수행해야 합니다. View 관련 리소스(RecyclerView 어댑터 등)는 onDestroyView에서 정리해야 합니다.
UIViewController는 iOS에서 화면을 관리하기 위한 기본 클래스입니다. 그 수명 주기는 UIKit이 자동으로 호출하는 일련의 메서드로 구성됩니다. 이 주기를 이해하는 것은 적절한 UI 초기화, 데이터 관리 및 메모리 처리에 매우 중요합니다.
| 메서드 | 호출 시점 | 일반적인 사용 |
|---|---|---|
| loadView | View Controller가 View 계층 구조를 로드할 때 | 스토리보드 없는 사용자 정의 초기화 |
| viewDidLoad | View가 메모리에 로드된 후(한 번) | UI 설정, 초기 데이터 로드 |
| viewWillAppear | View가 화면에 나타나기 전 | 데이터 업데이트, 알림 구독 |
| viewDidAppear | View가 화면에 나타난 후 | 애니메이션 시작, 추적 애니메이션 시작 |
| viewWillDisappear | View가 화면에서 사라지기 전 | 상태 저장, 알림 구독 취소 |
| viewDidDisappear | View가 화면에서 사라진 후 | 애니메이션 중지, 리소스 해제 |
| dealloc | View Controller가 소멸될 때 | 모든 리소스 해제 |
중요: viewDidLoad는 View Controller의 수명 동안 한 번만 호출됩니다. 나타날 때마다 데이터를 업데이트하려면 viewWillAppear를 사용하세요. viewWillAppear에서 NotificationCenter를 구독하는 경우 메모리 누수를 방지하기 위해 viewDidDisappear에서 반드시 구독을 취소하세요.
SwiftUI는 View 구조체를 통해 View의 수명 주기를 관리합니다. 콜백 메서드 대신 SwiftUI는 onAppear 및 onDisappear 수정자를 사용합니다. 전역 앱 상태의 경우 App 및 Scene 프로토콜을 통해 App Lifecycle이 사용됩니다. SwiftUI는 상태에 따라 View의 생성 및 소멸을 자동으로 관리하여 개발을 단순화하지만 View의 정체성과 수명을 이해해야 합니다.
struct ContentView: View {
var body: some View {
Text("Hello")
.onAppear {
print("View появилась")
}
.onDisappear {
print("View исчезла")
}
}
}
LifecycleOwner는 수명 주기가 있는 객체(Activity, Fragment)를 표시하는 Android Architecture Components의 인터페이스입니다. LifecycleObserver는 객체가 LifecycleOwner의 이벤트를 구독할 수 있게 하는 인터페이스입니다. 이들은 함께 현대 Android 개발에서 반응형 수명 주기 관리의 기초를 형성합니다.
onStart/onStop에서 명시적으로 메서드를 호출하는 대신 DefaultLifecycleObserver(@OnLifecycleEvent 어노테이션이 있는 더 이상 사용되지 않는 LifecycleObserver의 대체)를 사용하는 것이 좋습니다. 이는 Activity나 Fragment에 대한 직접적인 참조 없이 수명 주기에 반응해야 하는 ViewModel 및 기타 구성 요소를 위해 Google이 권장하는 접근 방식입니다.
class MyObserver : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
// Подписка на обновления
}
override fun onStop(owner: LifecycleOwner) {
// Отписка
}
}
IT Sectr에서는 모든 Android 프로젝트에서 LifecycleOwner를 사용합니다. ViewModel은 viewModelScope와 lifecycleScope를 통해 Activity의 LifecycleOwner를 구독하여 Activity가 소멸될 때 코루틴이 자동으로 취소되도록 보장합니다. 이는 메모리 누수를 방지하고 코드를 더 깔끔하고 안전하게 만듭니다.
자주 묻는 질문
Activity는 6가지 상태를 거칩니다: Created(onCreate), Started(onStart), Resumed(onResume), Paused(onPause), Stopped(onStop), Destroyed(onDestroy).
순서: loadView → viewDidLoad → viewWillAppear → viewDidAppear → viewWillDisappear → viewDidDisappear. viewDidLoad는 한 번 호출됩니다.
LifecycleOwner는 Activity 또는 Fragment의 수명 주기를 소유하는 Android Architecture Components의 구성 요소입니다. LifecycleObserver를 통해 이벤트를 구독할 수 있습니다.
iOS 앱은 5가지 상태를 거칩니다: Not Running, Inactive, Active, Background, Suspended. 전환은 UIApplicationDelegate를 통해 관리됩니다.
Saved State는 화면 회전 또는 프로세스 재생성 시 Activity/Fragment 상태를 보존하는 Android의 메커니즘입니다. onSaveInstanceState와 SavedStateHandle을 사용합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.