onStop — Android에서 Activity 생명주기의 메서드로, Activity가 사용자에게 더 이상 표시되지 않을 때 시스템에 의해 호출됩니다. 새 Activity가 완전히 덮은 후 또는 앱이 최소화될 때 Activity는 Stopped 상태로 전환됩니다. onStop 메서드에서 개발자는 애니메이션을 중지하고, 카메라 및 센서 리소스를 해제하며, 입력된 데이터의 초안을 저장해야 합니다. Android Vitals(Google, 2025)에 따르면 onStop을 올바르게 처리하면 앱 최소화 시 ANR(애플리케이션이 응답하지 않음) 수가 35% 감소합니다. onStop 후 시스템은 onRestart(화면으로 복귀) 또는 onDestroy(완전 종료)를 호출할 수 있습니다. Activity 생명주기에 대한 Android Developers 문서는 onStop을 표시 가능 상태와 표시 불가능 상태 사이의 경계로 설명합니다.
핵심 사항
onStop — AppCompatActivity 클래스(및 그 전신 Activity)의 콜백 메서드로, Android 운영 체제가 Activity가 사용자에게 완전히 표시되지 않을 때 호출합니다. 이 시점에서 Activity는 다른 Activity, 대화상자 창, 시스템 실행기 또는 잠금 화면에 의해 숨겨집니다. 생명주기 관점에서 onStop은 onPause 다음에 오며 Activity 개체와 그 상태가 메모리에 남아 있지만 Activity가 더 이상 화면에 표시되지 않음을 알립니다.
Activity가 Stopped(중지됨) 상태로 전환되면 RAM에 상태를 유지합니다 — 모든 필드, View 계층 구조 및 ViewModel이 계속 액세스 가능합니다. 이는 Stopped가 Activity가 완전히 제거되는 Destroyed(소멸됨) 상태와 구별됩니다. 시스템 UI는 메모리가 부족할 때 Stopped 상태의 앱 프로세스를 종료할 수 있습니다 — 이를 프로세스 종료라고 합니다. 개발자는 onStop 전에 호출되는 onSaveInstanceState()에 중요한 데이터(초안, 스크롤 위치)를 저장하여 프로세스 종료 시 복원을 보장해야 합니다.
Android 호환성 정의 문서(CDD) 버전 14+에 따르면 Stopped 상태의 프로세스는 OOM Killer에 의한 종료 우선순위가 낮습니다 — Background 단계의 프로세스보다는 낮지만 캐시된 프로세스보다는 높습니다. Google 통계에 따르면 68%의 프로세스 종료 사례는 Activity가 Paused 상태가 아닌 Stopped 상태일 때 발생합니다.
onStop은 Activity가 완전히 표시되지 않을 때 호출됩니다. 이유에 관계없이: 현재 위에 새 Activity 시작, 앱 최소화(홈 버튼), 화면 잠금, 수신 전화 또는 시스템 대화상자 열기. 이 모든 경우에서 Activity는 먼저 onPause(부분적 포커스 손실)를 받은 다음 onStop(완전한 표시 손실)을 받습니다.
onStop 호출의 주요 시나리오:
화면 회전 시 onStop이 호출되지 않는다는 점을 이해하는 것이 중요합니다 — 이 경우 Activity는 소멸(onPause → onStop → onDestroy)되고 다시 생성(onCreate → onStart → onResume)됩니다. 예외는 매니페스트의 android:configChanges="orientation" 플래그로, Activity 재생성을 방지하고 대신 onConfigurationChanged()를 호출합니다.
onStop은 Activity 생명주기 시퀀스에서 표시 상태와 표시 불가능 상태 사이의 중심 위치를 차지합니다. 전체 시퀀스: onCreate → onStart → onResume → (활성 상태) → onPause → onStop → onDestroy(또는 복귀 시 onRestart → onStart → onResume).
| 상태 | 메서드 | 표시 | 상호작용 | 메모리 |
|---|---|---|---|---|
| Created | onCreate | 없음 | 없음 | 할당됨 |
| Started | onStart | 부분 | 없음 | 전체 |
| Resumed | onResume | 전체 | 예 | 전체 |
| Paused | onPause | 부분 | 없음 | 전체 |
| Stopped | onStop | 없음 | 없음 | 전체* |
| Destroyed | onDestroy | 없음 | 없음 | 해제됨 |
*Stopped 상태에서 Activity는 메모리에 유지되지만 리소스 부족 시 시스템에 의해 종료될 수 있습니다. Stopped 프로세스 종료 우선순위는 마지막에서 두 번째로, 캐시된 빈 프로세스만 아래에 있습니다.
onStop과 onSaveInstanceState: 시스템은 동적 UI 상태를 저장하기 위해 onStop 전에 onSaveInstanceState(Bundle)을 호출합니다. 개발자는 이 메서드를 재정의하여 입력 필드 값, RecyclerView 위치 및 선택된 항목을 Bundle에 저장합니다. Activity가 소멸되지 않더라도(사용자가 단순히 최소화했다가 돌아온 경우) Bundle은 구성 변경 시 onCreate로 전달됩니다. Google은 Activity 외부에 존재하는 리포지토리 데이터나 ViewModel이 아닌 임시 UI 상태만 저장할 것을 권장합니다.
onStop에서 개발자는 Activity가 표시되지 않을 때 필요하지 않은 모든 리소스를 해제해야 합니다. 이렇게 하면 배터리, CPU 및 메모리 부하가 줄어들고 Activity로 돌아갈 때 ANR도 방지됩니다.
onStop에서 해제할 사항:
onStop에서 하지 말아야 할 것: 장기 실행 작업(데이터베이스에 대량 데이터 저장, 네트워크 요청, 복잡한 계산)을 수행하지 마십시오. onStop은 메인 스레드에서 실행되며 Activity로의 복귀를 차단합니다. 장기 작업의 경우 지연이 있는 WorkManager 또는 viewModelScope의 코루틴을 사용하십시오. ViewModel 리소스를 해제하지 마십시오 — ViewModel은 onStop에서 살아남으며 복귀 시 사용됩니다.
onPause와 onStop은 표시 손실 정도와 필수 작업 범위에서 다릅니다. onPause는 부분적 포커스 손실 시(예: 대화상자 창 또는 시스템 메뉴 열기) 호출되고, onStop은 완전한 표시 손실 시 호출됩니다. 이 차이는 각 단계에서 해제할 리소스를 선택하는 데 중요합니다.
| 특성 | onPause | onStop |
|---|---|---|
| 표시 수준 | 부분적으로 표시 | 완전히 표시되지 않음 |
| 포커스 | 손실 | 손실 |
| 실행 시간 | 최대 500ms | 최대 5초(ANR 타임아웃) |
| 해제할 리소스 | 중요한 것(미디어, 카메라) | 모든 표시 불가능한 것(센서, 애니메이션, 위치) |
| 복원 | onResume | onRestart → onStart → onResume |
| 프로세스 우선순위 | 높음(포그라운드) | 중간(백그라운드) |
일반 규칙: onPause에서는 다른 앱의 사용자 경험에 즉시 영향을 미치는 시스템 리소스(카메라, 미디어 플레이어)를 해제합니다. onStop에서는 Activity가 숨겨져 있을 때 필요하지 않은 다른 모든 리소스를 해제합니다. Google은 빠른 전환 시 onStop이 호출되지 않을 수 있으므로 onPause에서 중요한 사용자 데이터(이메일 초안, 설정)를 저장할 것을 권장합니다.
사용자가 숨겨진 Activity로 돌아가면 시스템은 onRestart → onStart → onResume을 호출합니다. onRestart 메서드는 Activity가 Stopped 상태에서 복귀하고 있음을 알립니다. 이는 onStop에서 해제된 UI와 리소스를 복원하는 중요한 단계입니다.
복귀 시 호출 순서:
앱 프로세스가 Stopped 상태에서 시스템에 의해 종료된 경우 onRestart 대신 onCreate가 호출되고 onSaveInstanceState의 Bundle이 상태 복원을 위해 전달됩니다. 이 시나리오(프로세스 종료)는 Android 앱에서 버그의 가장 흔한 원인 중 하나입니다: 개발자는 onRestart를 구현하지만 프로세스 종료 후 onCreate를 통한 복원을 고려하는 것을 잊습니다.
Activity 숨김 시 올바른 센서 구독 취소 및 애니메이션 중지를 보여줍니다. 화면으로 돌아가면 onStart에서 리소스가 복원됩니다.
class MainActivity : AppCompatActivity() {
private lateinit var sensorManager: SensorManager
private var accelerometer: Sensor? = null
private var rotationAnimator: ObjectAnimator? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
override fun onStart() {
super.onStart()
accelerometer?.let {
sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
}
rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
rotationAnimator?.apply {
duration = 3000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
start()
}
}
override fun onStop() {
super.onStop()
sensorManager.unregisterListener(sensorListener)
rotationAnimator?.cancel()
}
override fun onRestart() {
super.onRestart()
Log.d("MainActivity", "Activity가 Stopped 상태에서 복귀")
}
private val sensorListener = SensorEventListener { event, _ ->
Log.d("MainActivity", "가속도: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
}
}
코드는 onStart에서 가속도계 센서를 등록하고 무한 회전 애니메이션을 시작합니다. onStop에서 센서 등록이 취소되고 애니메이션이 취소됩니다 — 이는 Activity가 숨겨져 있을 때 배터리 소모를 방지합니다. onRestart → onStart를 통해 복귀한 후 리소스가 다시 생성됩니다.
ViewModel + SavedStateHandle을 사용하는 현대적인 접근 방식입니다. 수동 Bundle 처리 없이 onStop 중에 양식 데이터가 자동으로 저장됩니다.
class FormViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
var email: String
get() = savedStateHandle["email"] ?: ""
set(value) { savedStateHandle["email"] = value }
var message: String
get() = savedStateHandle["message"] ?: ""
set(value) { savedStateHandle["message"] = value }
}
class FormActivity : AppCompatActivity() {
private val viewModel: FormViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_form)
Log.d("FormActivity", "onCreate: email=${viewModel.email}")
}
override fun onStop() {
super.onStop()
Log.d("FormActivity", "onStop: 데이터가 SavedStateHandle에 저장됨")
}
}
SavedStateHandle은 onStop 전에 호출되는 onSaveInstanceState 중에 Bundle에 값을 자동으로 저장합니다. 화면 회전 또는 프로세스 종료 시 데이터가 손실 없이 복원됩니다. Google은 직접 onSaveInstanceState 대신 양식 및 초안에 SavedStateHandle을 권장합니다.
onStop으로 전환 중 비동기 데이터 저장을 위해 코루틴과 함께 lifecycleScope를 사용합니다. 코루틴은 메인 스레드를 차단하지 않고 IO 디스패처에서 실행됩니다.
class NoteActivity : AppCompatActivity() {
private val noteRepository = NoteRepository()
override fun onStop() {
lifecycleScope.launch(Dispatchers.IO) {
val text = findViewById<EditText>(R.id.note_content).text.toString()
noteRepository.saveDraft(text)
withContext(Dispatchers.Main) {
Log.d("NoteActivity", "초안이 onStop에서 저장됨")
}
}
super.onStop()
}
}
lifecycleScope.launch 코루틴은 Activity 생명주기가 종료되면 자동으로 취소됩니다. Dispatchers.IO를 사용하면 데이터베이스 또는 파일 쓰기가 Activity로의 복귀를 차단하지 않습니다. Google에 따르면 lifecycleScope의 코루틴은 onStop에서 비동기 작업을 수행하는 기본 방법입니다.
자주 묻는 질문
onStop — Activity가 더 이상 표시되지 않지만 Stopped 상태로 메모리에 남아 있습니다. 시스템은 onRestart를 통해 Activity를 복귀시킬 수 있습니다. onDestroy — Activity가 소멸되고 메모리가 해제됩니다. onDestroy 후에는 새 Activity 인스턴스(onCreate)를 생성해야만 복귀가 가능합니다.
예, 필수입니다. super.onStop()은 시스템 구성 요소(프래그먼트, LoaderManager, ViewModelStore)의 올바른 작동을 보장합니다. super.onStop()을 생략하면 메모리 누수와 잘못된 프래그먼트 복원이 발생할 수 있습니다. super.onStop()을 항상 마지막이나 처음에 호출하세요 — 순서는 중요하지 않지만 호출은 필수입니다.
각 생명주기 메서드에서 Log.d 또는 Timber를 사용하세요. Activity 태그로 logcat 필터를 활성화하세요. 프로덕션의 경우 Android Vitals을 사용하세요 — Google이 자동으로 생명주기 메트릭을 수집하고 Play Console에서 이상 징후를 표시합니다. ProcessLifecycleOwner를 통한 생명주기 모니터링도 가능합니다.
onStop에서 처리되지 않은 예외는 앱의 Force Close를 유발합니다. 시스템은 생명주기 콜백에서 예외를 캐치하지 않습니다. onStop에서 예외를 발생시킬 수 있는 작업(파일 작업, 네트워크)을 수행하는 경우 try-catch로 감싸고 super.onStop()을 중단하지 않고 오류를 로그에 기록하세요.
아니요, Activity의 Bitmap은 참조가 없으면 GC에 의해 수집됩니다. onStop에서 강제 해제(recycle())는 필요하지 않으며 오히려 해롭습니다 — Activity가 onRestart를 통해 복귀하면 Bitmap을 다시 로드해야 합니다. 이미지 로딩에는 Glide 또는 Coil을 사용하세요 — 이 라이브러리들은 자동으로 캐싱과 생명주기를 관리합니다.
요약
턴키 방식의 모바일 애플리케이션을 개발해 드립니다
IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.