onStop — метод життєвого циклу Activity в Android, що викликається системою, коли Activity перестає бути видимою для користувача. Activity переходить у стан Stopped після того, як нова Activity повністю закриває її, або при згортанні додатку. У методі onStop розробник зобов'язаний зупинити анімації, звільнити ресурси камери та сенсорів, зберегти чернетки введених даних. Згідно з Android Vitals (Google, 2025), коректна обробка onStop знижує кількість ANR (Application Not Responding) при згортанні додатку на 35%. Після onStop система може викликати onRestart (повернення на екран) або onDestroy (повне завершення). Документація Android Developers з життєвого циклу Activity описує onStop як межу між видимим і невидимим станом.
Головне
onStop — це метод-колбек класу AppCompatActivity (та його попередника Activity), який викликається операційною системою Android, коли Activity перестає бути повністю видимою для користувача. У цей момент Activity прихована іншою Activity, діалоговим вікном, системним лаунчером або екраном блокування. З точки зору життєвого циклу, onStop слідує після onPause і сигналізує, що Activity більше не видно на екрані, хоча сам об'єкт Activity та його стан залишаються в пам'яті.
Коли Activity переходить у стан Stopped (зупинено), вона зберігає свій стан в оперативній пам'яті — всі поля, View-ієрархія та ViewModel залишаються доступними. Це відрізняє Stopped від знищеного (Destroyed) стану, де Activity видаляється повністю. Системний UI може вбити процес додатку, що знаходиться в стані Stopped, при нестачі пам'яті — це так звана смерть процесу. Розробник зобов'язаний зберегти критичні дані (чернетки, позицію скролу) в onSaveInstanceState(), який викликається до onStop, щоб гарантувати відновлення при вбивстві процесу.
Згідно зі специфікацією Android Compatibility Definition Document (CDD) для версії 14+, процес у стані Stopped має знижений пріоритет при вбивстві OOM Killer — нижчий, ніж у процесів у фазі Background, але вищий, ніж у кешованих процесів. За статистикою Google, 68% випадків вбивства процесів відбуваються, коли Activity знаходиться в стані Stopped, а не Paused.
onStop викликається при повній втраті видимості Activity, незалежно від причини: запуск нової Activity поверх поточної, згортання додатку (натискання Home), блокування екрану, вхідний дзвінок або відкриття системного діалогу. У всіх цих випадках 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: Система викликає onSaveInstanceState(Bundle) перед onStop для збереження динамічного стану UI. Розробник перевизначає цей метод, щоб зберегти в Bundle значення полів введення, позицію RecyclerView, вибрані елементи. Навіть якщо Activity не буде знищена (користувач просто згорнув і повернувся), Bundle передається в onCreate при конфігураційних змінах. Google рекомендує зберігати лише транзитний UI-стан — не дані репозиторію або ViewModel, які живуть поза Activity.
В onStop розробник зобов'язаний звільнити всі ресурси, які не потрібні, коли Activity не видна. Це знижує навантаження на батарею, процесор та пам'ять, а також запобігає ANR при поверненні на активність.
Що звільняти в onStop:
Чого не робити в onStop: Не виконуйте тривалі операції — збереження великих даних у БД, мережеві запити, складні обчислення. onStop виконується на головному потоці і блокує повернення на Activity. Для тривалих операцій використовуйте WorkManager із затримкою або корутини в viewModelScope. Не звільняйте ресурси ViewModel — ViewModel переживає onStop і буде використана при поверненні.
onPause та onStop розрізняються ступенем втрати видимості та обсягом обов'язкових дій. onPause викликається при частковій втраті фокусу (наприклад, відкриття діалогового вікна або системного меню), onStop — при повній втраті видимості. Ця відмінність важлива для вибору, які ресурси звільняти на кожному етапі.
| Характеристика | onPause | onStop |
|---|---|---|
| Ступінь видимості | Частково видимо | Повністю невидимо |
| Фокус | Втрачений | Втрачений |
| Час виконання | До 500 мс | До 5 с (ANR-таймаут) |
| Ресурси для звільнення | Критичні (медіа, камера) | Всі невидимі (сенсори, анімації, локація) |
| Відновлення | onResume | onRestart → onStart → onResume |
| Пріоритет процесу | Високий (Foreground) | Середній (Background) |
Загальне правило: в onPause звільняйте системні ресурси, які негайно впливають на користувацький досвід іншого додатку (камера, медіаплеєр); в onStop — всі інші ресурси, не потрібні при прихованій Activity. Google рекомендує в onPause зберігати критичні користувацькі дані (чернетку листа, налаштування), оскільки onStop може не настати при швидкому перемиканні.
Коли користувач повертається на приховану Activity, система викликає onRestart → onStart → onResume. Метод onRestart сигналізує, що Activity повертається зі стану Stopped. Це важливий етап для відновлення UI та ресурсів, які були звільнені в onStop.
Послідовність викликів при поверненні:
Якщо процес додатку був вбитий системою в стані Stopped, onCreate викликається замість onRestart, а Bundle з onSaveInstanceState передається для відновлення стану. Цей сценарій (смерть процесу) — одна з найпоширеніших причин багів в 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. Дані форми зберігаються автоматично при onStop без ручного Bundle.
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 автоматично зберігає значення в Bundle при onSaveInstanceState, який викликається до onStop. При повороті екрану або вбивстві процесу дані відновлюються без втрати. Google рекомендує SavedStateHandle для форм та чернеток замість прямого onSaveInstanceState.
Використання lifecycleScope з корутинами для асинхронного збереження даних при переході в onStop. Корутина запускається в диспетчері 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. Система може повернути Activity через onRestart. onDestroy — Activity знищується, пам'ять звільняється. Після onDestroy повернення можливе лише через створення нового екземпляра Activity (onCreate).
Так, обов'язково. super.onStop() забезпечує коректну роботу системних компонентів: фрагментів, LoaderManager, ViewModelStore. Пропуск super.onStop() може викликати витоки пам'яті та некоректне відновлення фрагментів. Завжди викликайте super.onStop() останнім або першим — порядок не критичний, але виклик обов'язковий.
Використовуйте Log.d або Timber в кожному методі життєвого циклу. Увімкніть фільтр logcat за тегом вашої Activity. Для продакшену використовуйте Android Vitals — Google автоматично збирає метрики життєвого циклу та показує аномалії в Play Console. Також доступний lifecycle-моніторинг через ProcessLifecycleOwner.
Неперехоплений виняток в onStop викликає Force Close додатку. Система не перехоплює винятки в колбеках життєвого циклу. Якщо в onStop виконуються операції, які можуть викинути виняток (робота з файлами, мережею), обгортайте їх в try-catch і логуйте помилку, не перериваючи виконання super.onStop().
Ні, Bitmap в Activity буде зібраний GC, якщо на нього немає посилань. Примусове звільнення (recycle()) в onStop не потрібне і навіть шкідливе — якщо Activity повернеться через onRestart, Bitmap доведеться завантажувати заново. Використовуйте Glide або Coil для завантаження зображень — ці бібліотеки автоматично керують кешем та життєвим циклом.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також