onResume — 기본, Android에서 사용자 상호작용

저자: IT Sectr 게시일: 2026-03-04 읽는 시간: 10 분

onResume은 Activity 또는 Fragment가 포그라운드로 나와 입력 포커스를 받을 때 호출되는 Android 수명 주기 메서드입니다. 이 상태에서 화면은 사용자 상호작용을 위한 준비가 됩니다: 모든 터치 이벤트, 키 누름, 제스처가 이 컴포넌트로 전달됩니다. onResume은 Activity의 작업 상태로, 애플리케이션이 대부분의 시간을 보내는 곳입니다. 바로 여기에서 카메라를 열고, 비디오 재생을 시작하고, 음성 인식을 시작하고, 독점 액세스가 필요한 센서 리스너를 등록합니다. 전체 Activity 수명 주기에 대한 자세한 내용은 Activity Lifecycle 문서를 참조하세요.

주요 내용

  • onResume — 입력 포커스가 있는 포그라운드 Activity; onStart 후 또는 대화상자에서 돌아온 후 호출됨
  • 독점 리소스 — 카메라, 마이크, 비디오 캡처는 onResume에서 열고 onPause에서 닫음
  • onResume/onPause 쌍 — 완전한 포커스가 필요한 리소스는 이 쌍으로 관리; onResume에서 등록, onPause에서 해제
  • onResume vs onStart — onStart = 가시성, onResume = 상호작용; 대화상자는 onResume을 재정의하지만 onStart는 재정의하지 않음
  • 타이밍 — onResume은 빨라야 함; 여기서 긴 작업은 UI 응답성을 지연시킴
  • Fragment.onResume — Activity.onResume 후, Fragment가 상호작용 준비가 되면 호출됨
  • Jetpack에서의 onResume — lifecycleScope와 LiveData는 자동 구독 관리를 위해 onResume을 사용함

Android에서 onResume 메서드의 기본

onResume — Activity 수명 주기의 세 번째 메서드로, onStart 후에 호출되며 화면이 사용자와의 완전한 상호작용을 위해 준비되었음을 알립니다. 이 순간 Activity는 백 스택의 최상위에 있으며, 시스템은 모든 입력 이벤트를 Activity로 전달하고, 애플리케이션은 사용자의 적극적인 참여가 필요한 모든 작업(화상 통화, 게임, 오디오 녹음, Canvas 그리기)을 시작할 수 있습니다.

onResume은 “포그라운드 수명”(foreground lifetime)의 일부입니다 — onResume과 onPause 사이의 간격입니다. 이것은 Activity의 가장 활동적인 기간으로, 애플리케이션이 가장 많은 리소스를 소비합니다: 터치 처리를 위한 CPU, 애니메이션 렌더링을 위한 GPU, 비디오 캡처를 위한 카메라와 마이크. 수명 주기의 이 수준을 이해하는 것은 에너지 소비 최적화에 중요합니다 — onResume에서 열린 리소스는 onPause에서 즉시 닫아야 합니다.

Google I/O 2025에 따르면, Activity가 세션당 onResume 상태에서 보내는 평균 시간은 뉴스 애플리케이션의 경우 2~5분, 게임 및 메신저의 경우 15~30분입니다. 나머지 시간 동안 Activity는 onPause, onStop 또는 onDestroy 상태에 있습니다. 이는 특히 onResume 코드를 최적화하는 것이 성능과 배터리 수명에 가장 큰 이점을 제공한다는 것을 의미합니다.

Activity에서의 onResume

Activity에서 onResume 메서드는 화면이 입력 포커스를 받을 때마다 호출됩니다 — 첫 번째 실행 시, 다른 Activity에서 돌아올 때, 대화상자를 닫을 때, 장치 잠금을 해제할 때. 이것은 세션 중에 여러 번 호출될 수 있는 “핫” 메서드이며, 구현은 가능한 한 가벼워야 합니다.

kotlin
class CameraActivity : AppCompatActivity() {
    private var cameraProvider: ProcessCameraProvider? = null
    private var preview: Preview? = null

    override fun onResume() {
        super.onResume()
        val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
        cameraProviderFuture.addListener({
            cameraProvider = cameraProviderFuture.get()
            val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
            preview = Preview.Builder().build().also {
                it.setSurfaceProvider(binding?.viewFinder?.surfaceProvider)
            }
            try {
                cameraProvider?.unbindAll()
                cameraProvider?.bindToLifecycle(
                    this, cameraSelector, preview
                )
            } catch (e: Exception) {
                Log.e("Camera", "Failed to bind camera", e)
            }
        }, ContextCompact.getMainExecutor(this))
    }

    override fun onPause() {
        super.onPause()
        cameraProvider?.unbindAll()
        preview = null
    }
}

CameraX 예제는 onResume/onPause의 고전적인 사용을 보여줍니다: 카메라는 한 번에 하나의 애플리케이션만 사용할 수 있는 독점 리소스입니다. bindToLifecycle을 통해 카메라를 수명 주기에 바인딩하면 onPause에서 카메라가 자동으로 닫히지만, 명시적인 unbindAll 호출은 즉각적인 해제를 보장합니다. 이는 Activity 간 전환 시 특히 중요합니다: 다른 Activity가 열기를 시도하기 전에 카메라를 해제해야 합니다.

Fragment에서의 onResume

Fragment의 onResume은 해당 Fragment를 포함하는 Activity가 onResume을 받은 후에 호출됩니다. 그러나 FragmentManager와 ViewPager의 특성으로 인해 Fragment의 onResume 호출 시점은 Activity에 비해 지연될 수 있습니다. 예를 들어, offscreenPageLimit = 1인 ViewPager의 Fragment는 Activity 시작 시가 아니라 현재 페이지가 될 때만 onResume을 받습니다.

kotlin
class VideoPlayerFragment : Fragment() {
    private var exoPlayer: ExoPlayer? = null

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        exoPlayer = ExoPlayer.Builder(requireContext()).build()
        binding?.playerView?.player = exoPlayer
    }

    override fun onResume() {
        super.onResume()
        exoPlayer?.play()
        if (userVisibleHint) {
            startBiometricAuth()
        }
    }

    override fun onPause() {
        exoPlayer?.pause()
        stopBiometricAuth()
        super.onPause()
    }
}

Fragment.onResume의 userVisibleHint 검사는 ViewPager와 관련이 있습니다: Fragment가 onResume을 받을 수 있지만 인접한 페이지에 의해 숨겨져 있을 수 있습니다(예: 애니메이션 전환 중). 이러한 경우 가시성 확인 없이 onResume에서 비디오나 생체 인식을 시작하면 예기치 않은 동작이 발생합니다. Fragment 1.5.0부터는 ViewPager2에서 프래그먼트 수명 주기를 정밀하게 제어하기 위해 FragmentTransaction.setMaxLifecycle()을 사용하는 것이 좋습니다.

onResume vs onStart: 각각 사용해야 할 때

개발자들은 종종 onStart와 onResume을 혼동하여 잘못된 메서드에 코드를 배치합니다. 주요 규칙: onStart — 가시성 동안 작동하는 리소스용; onResume — 입력 포커스가 필요한 리소스용. 구체적인 시나리오와 올바른 메서드 선택을 살펴보겠습니다.

작업메서드근거
위치 정보 구독onStart / onStopGPS는 부분 가시성에서도 작동 가능
카메라 열기onResume / onPause카메라는 독점 리소스
BroadcastReceiveronStart / onStop시스템 이벤트는 포커스 불필요
비디오 재생onResume / onPause비디오는 사용자에게 보여야 함
Bluetooth 스캔onStart / onStop스캔은 백그라운드에서 실행 가능
음성 녹음기(MediaRecorder)onResume / onPause녹음에는 활성 UI 필요
센서 리스너onResume / onPause게임 및 제스처용 센서
데이터 업데이트onStart표시 시 최신 데이터 필요

실용적인 규칙: 대화상자가 나타날 때 작업이 중단되어야 하는 경우 — onResume/onPause를 사용합니다. 화면이 부분적으로 가려져도 작업을 계속할 수 있는 경우 — onStart/onStop을 사용합니다. 예를 들어, 비디오 플레이어는 대화상자가 열리면 비디오를 일시 중지해야 하고(onPause), 위치 정보는 업데이트를 계속할 수 있습니다(onStart 유지).

독점 리소스 관리

독점 리소스는 특정 시점에 하나의 애플리케이션만 사용할 수 있는 장치 구성 요소입니다. 카메라, 마이크, 비디오 출력(MediaProjection), 읽기 모드의 NFC 어댑터, 액세서리 모드의 USB 장치 — 이러한 모든 리소스는 onResume에서 열고 onPause에서 해제해야 합니다.

MediaRecorder 작업

MediaRecorder는 오디오 및 비디오 녹음에 사용됩니다. 권한 요청 및 MediaRecorder 준비는 onCreate에서 수행되고, 녹음은 onResume에서 시작됩니다. 사용자가 다른 애플리케이션으로 전환하면 onPause가 녹음을 일시 중지하고 onResume이 재개합니다. 이것은 음성 녹음기 및 비디오 녹화 애플리케이션의 표준 동작입니다.

kotlin
private var mediaRecorder: MediaRecorder? = null
private var isRecording = false

override fun onResume() {
    super.onResume()
    if (isRecording) {
        mediaRecorder?.resume()
    }
}

override fun onPause() {
    if (isRecording) {
        mediaRecorder?.pause()
    }
    super.onPause()
}

BiometricPrompt와 onResume

생체 인증(BiometricPrompt)은 Activity가 onResume 상태에 있을 때만 호출해야 합니다. onCreate나 onStart에서 호출하면 Activity 초기화가 완료되기 전에 생체 인증 대화상자가 나타나 결과 처리가 잘못될 수 있습니다. onResume에서 호출하면 생체 인증 창이 올바른 컨텍스트에 표시됩니다.

패턴 및 권장 사항

상용 프로젝트에서 사용되는 onResume 작업의 세 가지 검증된 패턴을 살펴보겠습니다: 비활성 타이머 재설정, 표시 데이터 업데이트, Jetpack Navigation 통합.

비활성 타이머 재설정

민감한 데이터(은행, 의료 기록)가 있는 애플리케이션에서 onResume은 자동 로그아웃 타이머를 재설정하는 데 사용됩니다. 사용자가 애플리케이션과 적극적으로 상호작용하는 경우 화면 전환 시마다 onResume이 호출되고 타이머가 재설정됩니다. 사용자가 애플리케이션을 최소화하면 onPause가 타이머를 중지하고, 돌아올 때 onResume이 타이머를 재설정하거나 재인증을 요청합니다.

돌아올 때 데이터 업데이트

화면으로 돌아올 때마다 최신 데이터를 표시해야 하는 목록은 onResume에서 업데이트됩니다. 예를 들어, 사용자가 다른 Activity에서 새 항목을 만들고 뒤로 이동하면 onResume이 로컬 데이터베이스 또는 ViewModel 캐시에서 목록을 다시 로드합니다. 이렇게 하면 수동 notifyDataSetChanged 호출 없이 데이터 일관성이 보장됩니다.

kotlin
override fun onResume() {
    super.onResume()
    // ActivityResultLauncher가 결과를 반환했습니다 — 목록 업데이트 중
    viewModel.refreshList()
    // 비활성 타이머 재설정
    inactivityTimer.reset()
}

Jetpack Navigation과 onResume

Jetpack Navigation에서 프래그먼트의 onResume은 뒤로 가기 탐색을 통해 프래그먼트로 돌아올 때마다 호출됩니다. 이 속성은 UI 상태를 재설정하는 데 사용됩니다: 키보드 숨기기, 검색 필드 지우기, 툴바 제목 업데이트. OnBackPressedCallback을 onResume과 결합하면 코드 중복 없이 탐색을 완전히 제어할 수 있습니다.

자주 묻는 질문

간단히 말해 onResume과 onStart의 차이점은 무엇인가요?

onStart — 화면이 보입니다. onResume — 화면이 활성화되고 상호작용할 준비가 되었습니다. 상상해보세요: TV를 보고 있습니다(onStart), 하지만 리모컨을 집습니다(onResume). TV는 항상 보이지만, 상호작용은 리모컨으로만 시작됩니다. 누군가 TV를 커튼으로 가리면 — 화면이 더 이상 보이지 않게 됩니다(onStop). 누군가 리모컨을 빼앗으면 — 상호작용이 중지됩니다(onPause), 하지만 TV는 여전히 보입니다.

onResume은 얼마나 자주 호출되나요?

onResume은 Activity가 입력 포커스를 받을 때마다 호출됩니다. 최소값은 한 번(실행 시)입니다. 최대값은 사용 시나리오에 따라 다릅니다: 화면 전환, 대화상자 열기, 장치 빠른 잠금 및 잠금 해제 — 이러한 각 시나리오는 화면으로 돌아올 때 onResume을 호출합니다.

카메라를 열기에 onResume이 가장 좋은 이유는 무엇인가요?

카메라는 한 번에 하나의 애플리케이션만 사용할 수 있는 독점 리소스입니다. onCreate나 onStart에서 카메라를 열면 애플리케이션이 비활성 상태일 때도 다른 앱에 대해 잠긴 상태로 유지됩니다. onResume은 Activity가 포그라운드에 있을 때만 카메라가 열려 있음을 보장하고, onPause가 즉시 닫습니다. 이것은 CameraX 및 Camera2 API 문서에 명시된 Android 개발 표준입니다.

onStart 후에 onResume이 호출되지 않을 수 있나요?

네, Activity가 나타난 직후 다른 Activity에 의해 가려지면 onResume이 발생하지 않을 수 있습니다. 예를 들어, Activity A가 onCreate 또는 onStart 메서드에서 Activity B를 시작합니다. 이 경우 A는 onStart → onPause → onStop을 받고 onResume을 건너뜁니다. 시스템은 Activity A가 입력 포커스를 받지 않았기 때문에 onResume을 호출하지 않습니다.

onResume에서 하면 안 되는 것은 무엇인가요?

onResume에서는 긴 동기 작업을 수행해서는 안 됩니다: 네트워크에서 대용량 데이터 로드, 복잡한 SQL 쿼리, 이미지 처리. onResume은 UI 스레드에서 실행되며, 100~200ms 이상의 차단은 인터페이스 응답 지연을 유발합니다. 모든 무거운 작업은 비동기식이어야 합니다 — 코루틴, RxJava 또는 WorkManager를 통해. 또한 확인 없이 onResume에서 finish()를 호출하는 것은 권장되지 않습니다 — 재생성의 무한 루프가 발생할 수 있습니다.

요약

  • onResume — 입력 포커스가 있는 포그라운드 상태; Activity가 사용자 상호작용 준비 완료
  • 독점 리소스 — 카메라, 마이크, 비디오 캡처는 onResume에서 열고 onPause에서 닫음
  • onResume vs onStart — onStart는 가시 리소스용, onResume은 활성 리소스용; 대화상자는 onResume을 중단하지만 onStart는 중단하지 않음
  • 성능 — onResume은 가벼워야 함; 모든 무거운 작업은 비동기식
  • Fragment.onResume — ViewPager에서 가시성에 따라 다름; userVisibleHint 확인 또는 setMaxLifecycle 사용
  • 일반적인 작업 — 타이머 재설정, 돌아올 때 데이터 업데이트, BiometricPrompt 관리
  • onResume/onPause 쌍 — 독점 액세스 권한이 있는 리소스는 이 쌍으로만 관리

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기