전체 글
약 2분

안드로이드를 만들며 8 — MainActivity의 생명주기 처리를 Compose로 옮기기

MainActivity에서 결제와 인앱 업데이트의 생명주기를 직접 처리하고 있었습니다. AppLifecycleManager로 관찰 코드를 옮겨 등록과 해제를 함께 두고, 콜백이 최신 게이트를 참조하도록 정리했습니다.

#android #compose #lifecycle #구조 #리팩토링

들어가며

결제와 인앱 업데이트를 붙이면서 MainActivity에 생명주기 처리가 쌓였습니다. 업데이트 재개는 onResume, 업데이트와 결제 자원 정리는 onDestroy에 있었습니다.

Activity에 나뉘어 있던 생명주기 처리

override fun onResume() {
    super.onResume()
    updateGate.onResume()
}

override fun onDestroy() {
    updateGate.onDestroy()
    if (::billing.isInitialized) billing.close()
    super.onDestroy()
}

결제나 업데이트 연결을 손볼 때마다 두 콜백을 오가야 했습니다. 화면은 Compose로 구성하고 있었으니, 이 연결도 별도 컴포저블로 옮겨 보기로 했습니다.

AppLifecycleManager에 모은 생명주기 연결

AppLifecycleManager에서 현재 LifecycleOwner를 얻고, DisposableEffect 안에서 관찰자를 등록하도록 했습니다.

@Composable
fun AppLifecycleManager(
    updateGate: UpdateGate,
    billingGate: BillingGate
) {
    val lifecycleOwner = LocalLifecycleOwner.current
    val currentUpdateGate = rememberUpdatedState(updateGate)
    val currentBillingGate = rememberUpdatedState(billingGate)

    DisposableEffect(lifecycleOwner) {
        val observer = LifecycleEventObserver { _, event ->
            when (event) {
                Lifecycle.Event.ON_RESUME -> {
                    currentUpdateGate.value.onResume()
                }
                Lifecycle.Event.ON_DESTROY -> {
                    currentUpdateGate.value.onDestroy()
                    currentBillingGate.value.close()
                }
                else -> {}
            }
        }

        lifecycleOwner.lifecycle.addObserver(observer)

        onDispose {
            lifecycleOwner.lifecycle.removeObserver(observer)
        }
    }
}

ON_RESUME에서는 업데이트 확인을 이어가고, ON_DESTROY에서는 게이트를 정리합니다. 관찰자를 등록하고 해제하는 코드도 같은 블록에서 읽을 수 있습니다.

다만 onDispose가 게이트까지 닫는 것은 아닙니다. 여기서는 관찰자만 제거합니다. 게이트 정리는 관찰 중 받은 ON_DESTROY에 달려 있으므로, 두 동작을 같은 것으로 읽으면 안 됩니다.

콜백이 처음의 게이트를 계속 참조하지 않도록

게이트는 rememberUpdatedState로 감쌌습니다.

val currentUpdateGate = rememberUpdatedState(updateGate)

DisposableEffect의 키는 lifecycleOwner입니다. 이 키가 같으면 updateGate 인스턴스가 바뀌어도 효과가 다시 실행되지 않습니다. 콜백이 updateGate를 직접 참조하면 처음 만들어졌을 때의 값을 계속 사용할 수 있습니다.

rememberUpdatedState를 사용하면 콜백은 .value에서 최신 게이트를 읽습니다. 게이트 값이 바뀌었다는 이유만으로 생명주기 관찰자를 제거하고 다시 등록할 필요가 없어집니다.

마치며

생명주기 연결을 옮긴 뒤 MainActivity의 onResume과 onDestroy 오버라이드를 제거했습니다. setContent 안에서는 다음처럼 호출합니다.

setContent {
    AppLifecycleManager(updateGate, billing)
    // …
}

이제 결제와 업데이트의 생명주기 연결은 AppLifecycleManager에서 고칩니다.