Engineering note · Android

안드로이드 LifecycleOwner is attempting to register while current state is RESUMED 크래시 해결

2025년 01월 24일이현수
태그androidlifecycle

registerForActivityResult 호출 시 생명주기가 STARTED/RESUMED 상태로 진입해 발생한 IllegalStateException 크래시 원인과 onCreate 동기 등록 해결법.

웹뷰 파일 업로드 처리를 위해 WebChromeClient를 초기화하던 중, 특정 조건에서 지연을 적용했더니 앱에서 크래시가 났다.

text
FATAL EXCEPTION: main
Process: com.example.myapp, PID: 22253
java.lang.IllegalStateException: LifecycleOwner com.example.myapp.MainActivity@df4a320 is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
    at androidx.activity.result.ActivityResultRegistry.register(ActivityResultRegistry.java:123)
    at androidx.activity.ComponentActivity.registerForActivityResult(ComponentActivity.java:833)
    at com.example.myapp.CustomWebChromeClient.<init>(CustomWebChromeClient.kt:38)
    at com.example.myapp.MainActivity.initializeWebView(MainActivity.kt:94)

예외 메시지가 아주 명확하다. "LifecycleOwner가 현재 RESUMED 상태인데 뒤늦게 결과를 등록하려 했다. 반드시 Activity가 STARTED 되기 전에 register를 호출해야 한다" 는 내용이다.

문제가 된 코드는 웹뷰 파일 선택 카메라/갤러리 응답을 받기 위해 WebChromeClient 내부 생성자에 적어둔 registerForActivityResult였다.

kotlin
class CustomWebChromeClient(var activity: MainActivity): WebChromeClient() {
    // 인스턴스 생성 시 Activity Result API 등록
    val launcher = activity.registerForActivityResult(
        ActivityResultContracts.StartActivityForResult()
    ) { result ->
        // 카메라/갤러리 이미지 선택 결과 처리
    }
}

기존에는 MainActivity.onCreate() 안에서 곧바로 CustomWebChromeClient를 동기 생성했기 때문에 문제가 없었다.

하지만 성능 측정 테스트를 진행하며 웹뷰 초기화 로직(initializeWebView())을 1초 비동기 지연 시킨 것이 화근이었다. 1초 대기하는 동안 이미 onResume 상태로 넘어가 버렸고, CustomWebChromeClient 만들 때 예외가 발생했다.

안드로이드 액티비티 생명주기와 registerForActivityResult 안전 등록 시점

kotlin
class MainActivity : AppCompatActivity() {

    private lateinit var webChromeClient: CustomWebChromeClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 1. registerForActivityResult를 품은 클라이언트 인스턴스는 onCreate 시점에 즉시 동기 생성
        webChromeClient = CustomWebChromeClient(this)

        // 2. 비동기 지연(delay)이 필요한 네트워크/웹뷰 URL 로딩 로직만 따로 지연 처리
        Handler(Looper.getMainLooper()).postDelayed({
            setupWebView()
        }, 1000)
    }

    private fun setupWebView() {
        binding.webView.webChromeClient = webChromeClient
        binding.webView.loadUrl("https://example.com")
    }
}

registerForActivityResult() 는 안드로이드의 액티비티나 프래그먼트의 LifecycleOwner 생명주기 CREATED 까지만 등록이 가능하다. 프로세스가 사망 후 복원될 때 복구 상태를 보장해야 하기 때문이다. 즉, STARTED 상태로 넘어가기 전 주로 onCreate 최상단 시점에 런처 인스턴스 등록이 완료되어야 한다.