생명주기 콜백을 직접 만지지 않고, 자원이 스스로 따라가게 만드는 구조.
콜백을 직접 쓰면 무엇이 나쁜가
// Activity 가 부풀어 오른다
override fun onStart() {
super.onStart()
locationClient.start(); analytics.startSession(); player.prepare()
}
override fun onStop() {
super.onStop()
locationClient.stop(); analytics.endSession(); player.release()
}
- 자원 하나를 추가할 때마다 Activity 두 곳을 고친다
- 한 쪽만 고치면 누수다 — 컴파일러가 안 잡아 준다
- Activity 가 모든 자원의 수명을 알아야 한다
자원이 스스로 따라가게 한다
class LocationTracker(
private val client: FusedLocationProviderClient
) : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) { client.requestLocationUpdates(...) }
override fun onStop(owner: LifecycleOwner) { client.removeLocationUpdates(...) }
}
// Activity 는 한 줄만 쓴다
lifecycle.addObserver(LocationTracker(client))
관심사가 뒤집혔다
- 전: Activity 가 모든 자원의 수명을 안다
- 후: 각 자원이 자기 수명을 안다
이미 이 방식으로 만들어진 것들
-
lifecycleScope — 화면이 파괴되면 코루틴이 취소된다
-
viewModelScope — ViewModel 이 사라지면 취소된다
-
repeatOnLifecycle — STARTED 아래로 내려가면 수집을 멈춘다
-
LiveData — 활성 상태에서만 관찰자에게 전달한다
-
CameraX / ExoPlayer — LifecycleOwner 를 넘기면 알아서 붙었다 떨어진다
-
"생명주기를 넘기면 알아서 한다" 가 안드로이드 라이브러리의 공통 패턴이다
앱 전체 전경/배경도 관찰할 수 있다
ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) { /* 앱이 전경으로 */ }
override fun onStop(owner: LifecycleOwner) { /* 앱이 배경으로 */ }
})
Activity 하나의 onStart 와 다르다
- 화면 A → B 로 이동해도 앱은 계속 전경이므로 불리지 않는다
- 세션 관리 · 잠금 화면 재인증에 쓴다
면접 함정
- ❌
LifecycleObserver인터페이스에@OnLifecycleEvent를 쓴다 → 이 애노테이션 방식은 폐기됐다.DefaultLifecycleObserver를 구현한다. - ❌ "옵저버를 제거해야 한다" → 해당
Lifecycle이 파괴되면 자동으로 정리된다.
Lifecycle의 상태와 이벤트
- 상태(State) — INITIALIZED · CREATED · STARTED · RESUMED · DESTROYED 이벤트(Event) ON_CREATE · ON_START · ON_RESUME · ON_PAUSE · ON_STOP · ON_DESTROY
상태는 '지금 어디에 있나', 이벤트는 '무엇이 방금 일어났나' 다
현재 상태를 물어볼 수도 있다
- if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) { ... }
Compose에서 생명주기 이벤트를 받는다
@Composable
fun OnLifecycleEvent(onEvent: (Lifecycle.Event) -> Unit) {
val owner = LocalLifecycleOwner.current
val current by rememberUpdatedState(onEvent)
DisposableEffect(owner) {
val obs = LifecycleEventObserver { _, e -> current(e) }
owner.lifecycle.addObserver(obs)
onDispose { owner.lifecycle.removeObserver(obs) }
}
}
앱 전경/배경 판별의 실제 용도
-
백그라운드 5분 뒤 재진입 시 재인증 요구 (금융 앱)
-
세션 시작/종료 분석 이벤트
-
배경으로 갈 때 민감 화면을 가린다 (최근 앱 미리보기 대비)
- window.setFlags(WindowManager.LayoutParams.FLAG_SECURE, ...)
-
Activity 하나의 onStop 으로는 '화면 전환' 과 '앱 이탈' 을 구분할 수 없다