onStop — приховування Activity у життєвому циклі Android

Автор: IT Sectr Опубліковано: 2026-03-04 Час читання: 9 хв

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 — метод, що викликається при повній втраті видимості Activity, але Activity все ще знаходиться в пам'яті.
  • Після onStop Activity переходить у стан Stopped — жива в пам'яті, але не видна і не взаємодіє з користувачем.
  • Система може викликати onRestart → onStart → onResume при поверненні на Activity або onDestroy при завершенні.
  • В onStop необхідно звільнити ресурси: зупинити анімації, відключити сенсори та камеру, зберегти проміжні дані.
  • Коректна реалізація onStop — ключовий фактор стабільності додатку при багатозадачності та згортанні.

Що таке onStop в Android?

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: сценарії та порядок

onStop викликається при повній втраті видимості Activity, незалежно від причини: запуск нової Activity поверх поточної, згортання додатку (натискання Home), блокування екрану, вхідний дзвінок або відкриття системного діалогу. У всіх цих випадках Activity спочатку отримує onPause (часткова втрата фокусу), а потім onStop (повна втрата видимості).

Основні сценарії виклику onStop:

  • Запуск нової Activity поверх поточної — поточна Activity отримує onPause, потім onStop; нова Activity проходить onCreate → onStart → onResume.
  • Згортання додатку (Home) — Activity переходить в onPause → onStop за 200–300 мс, залишається в пам'яті в стані Stopped.
  • Блокування екрану — система викликає onPause → onStop, оскільки екран блокування повністю перекриває Activity.
  • Вхідний дзвінок — телефонний додаток (Dialer) запускається поверх, поточна Activity переходить в onStop.
  • Перемикання на інший додаток (Recent Apps) — Activity приховується, отримує onStop, але залишається в кеші процесів.

Важливо розуміти, що onStop не викликається при повороті екрану — в цьому випадку Activity знищується (onPause → onStop → onDestroy) і створюється заново (onCreate → onStart → onResume). Виняток — прапорець android:configChanges="orientation" в маніфесті, при якому Activity не перестворюється, а отримує виклик onConfigurationChanged().

onStop у життєвому циклі Activity

onStop займає центральне місце в послідовності життєвого циклу Activity між видимим і невидимим станом. Повна послідовність: onCreate → onStart → onResume → (активний стан) → onPause → onStop → onDestroy (або onRestart → onStart → onResume при поверненні).

СтанМетодВидимістьВзаємодіяПам'ять
CreatedonCreateНемаєНемаєВиділяється
StartedonStartЧастковоНемаєПовна
ResumedonResumeПовнаТакПовна
PausedonPauseЧастковоНемаєПовна
StoppedonStopНемаєНемаєПовна*
DestroyedonDestroyНемаєНемаєЗвільнена

*У стані Stopped Activity зберігається в пам'яті, але може бути вбита системою при нестачі ресурсів. Пріоритет вбивства Stopped-процесів — передостанній, вище тільки кешовані порожні процеси.

onStop і onSaveInstanceState: Система викликає onSaveInstanceState(Bundle) перед onStop для збереження динамічного стану UI. Розробник перевизначає цей метод, щоб зберегти в Bundle значення полів введення, позицію RecyclerView, вибрані елементи. Навіть якщо Activity не буде знищена (користувач просто згорнув і повернувся), Bundle передається в onCreate при конфігураційних змінах. Google рекомендує зберігати лише транзитний UI-стан — не дані репозиторію або ViewModel, які живуть поза Activity.

Які ресурси звільняти в onStop

В onStop розробник зобов'язаний звільнити всі ресурси, які не потрібні, коли Activity не видна. Це знижує навантаження на батарею, процесор та пам'ять, а також запобігає ANR при поверненні на активність.

Що звільняти в onStop:

  • Анімації та транзиції — зупинити ObjectAnimator, ValueAnimator, ViewPropertyAnimator. Працююча анімація невидимої Activity — марна трата GPU-циклів.
  • Сенсори (Sensors) — відписатися від SensorManager (акселерометр, гіроскоп, магнетометр). Сенсори споживають енергію навіть при прихованій Activity.
  • Камера та мікрофон — звільнити Camera2 або CameraX, зупинити MediaRecorder. Залишати камеру активною при прихованій Activity заборонено політикою Google Play.
  • LocationListener — відписатися від FusedLocationProviderClient або LocationManager. Геолокація — найенергоємніший ресурс.
  • Мережеві слухачі — закрити WebSocket, скасувати HTTP-запити, які не потрібні у фоновому режимі.
  • MediaPlayer та ExoPlayer — поставити на паузу або зупинити, якщо відтворення не повинно продовжуватися у фоновому режимі.

Чого не робити в onStop: Не виконуйте тривалі операції — збереження великих даних у БД, мережеві запити, складні обчислення. onStop виконується на головному потоці і блокує повернення на Activity. Для тривалих операцій використовуйте WorkManager із затримкою або корутини в viewModelScope. Не звільняйте ресурси ViewModel — ViewModel переживає onStop і буде використана при поверненні.

Відмінність onStop від onPause

onPause та onStop розрізняються ступенем втрати видимості та обсягом обов'язкових дій. onPause викликається при частковій втраті фокусу (наприклад, відкриття діалогового вікна або системного меню), onStop — при повній втраті видимості. Ця відмінність важлива для вибору, які ресурси звільняти на кожному етапі.

ХарактеристикаonPauseonStop
Ступінь видимостіЧастково видимоПовністю невидимо
ФокусВтраченийВтрачений
Час виконанняДо 500 мсДо 5 с (ANR-таймаут)
Ресурси для звільненняКритичні (медіа, камера)Всі невидимі (сенсори, анімації, локація)
ВідновленняonResumeonRestart → onStart → onResume
Пріоритет процесуВисокий (Foreground)Середній (Background)

Загальне правило: в onPause звільняйте системні ресурси, які негайно впливають на користувацький досвід іншого додатку (камера, медіаплеєр); в onStop — всі інші ресурси, не потрібні при прихованій Activity. Google рекомендує в onPause зберігати критичні користувацькі дані (чернетку листа, налаштування), оскільки onStop може не настати при швидкому перемиканні.

onStop → onRestart: повернення на екран

Коли користувач повертається на приховану Activity, система викликає onRestart → onStart → onResume. Метод onRestart сигналізує, що Activity повертається зі стану Stopped. Це важливий етап для відновлення UI та ресурсів, які були звільнені в onStop.

Послідовність викликів при поверненні:

  • onRestart() — Activity повідомляється, що вона буде показана знову. Типові дії: перезавантаження даних, оновлення списків.
  • onStart() — Activity стає видимою, але ще не активною. Тут повторно ініціалізуються ресурси, звільнені в onStop.
  • onResume() — Activity отримує фокус і готова до взаємодії. Запускаються анімації, реєструються сенсори.

Якщо процес додатку був вбитий системою в стані Stopped, onCreate викликається замість onRestart, а Bundle з onSaveInstanceState передається для відновлення стану. Цей сценарій (смерть процесу) — одна з найпоширеніших причин багів в Android-додатках: розробники реалізують onRestart, але забувають врахувати відновлення через onCreate після вбивства процесу.

Приклади коду з onStop на Kotlin

Приклад 1: Базова реалізація onStop зі звільненням сенсорів

Демонструє коректне відписування від сенсорів та зупинку анімації при приховуванні Activity. Після повернення на екран ресурси відновлюються в onStart.

kotlin
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 ресурси перестворюються.

Приклад 2: onStop зі збереженням стану через SavedStateHandle

Сучасний підхід з використанням ViewModel + SavedStateHandle. Дані форми зберігаються автоматично при onStop без ручного Bundle.

kotlin
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.

Приклад 3: lifecycleScope для операцій в onStop

Використання lifecycleScope з корутинами для асинхронного збереження даних при переході в onStop. Корутина запускається в диспетчері IO, не блокуючи головний потік.

kotlin
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 від onDestroy?

onStop — Activity перестає бути видимою, але залишається в пам'яті в стані Stopped. Система може повернути Activity через onRestart. onDestroy — Activity знищується, пам'ять звільняється. Після onDestroy повернення можливе лише через створення нового екземпляра Activity (onCreate).

Чи обов'язково викликати super.onStop()?

Так, обов'язково. super.onStop() забезпечує коректну роботу системних компонентів: фрагментів, LoaderManager, ViewModelStore. Пропуск super.onStop() може викликати витоки пам'яті та некоректне відновлення фрагментів. Завжди викликайте super.onStop() останнім або першим — порядок не критичний, але виклик обов'язковий.

Як перевірити, що onStop був викликаний?

Використовуйте Log.d або Timber в кожному методі життєвого циклу. Увімкніть фільтр logcat за тегом вашої Activity. Для продакшену використовуйте Android Vitals — Google автоматично збирає метрики життєвого циклу та показує аномалії в Play Console. Також доступний lifecycle-моніторинг через ProcessLifecycleOwner.

Що станеться, якщо в onStop викинути виняток?

Неперехоплений виняток в onStop викликає Force Close додатку. Система не перехоплює винятки в колбеках життєвого циклу. Якщо в onStop виконуються операції, які можуть викинути виняток (робота з файлами, мережею), обгортайте їх в try-catch і логуйте помилку, не перериваючи виконання super.onStop().

Чи потрібно звільняти Bitmap в onStop?

Ні, Bitmap в Activity буде зібраний GC, якщо на нього немає посилань. Примусове звільнення (recycle()) в onStop не потрібне і навіть шкідливе — якщо Activity повернеться через onRestart, Bitmap доведеться завантажувати заново. Використовуйте Glide або Coil для завантаження зображень — ці бібліотеки автоматично керують кешем та життєвим циклом.

Підсумки

  • onStop — метод життєвого циклу Activity, що викликається при повній втраті видимості. Activity залишається в пам'яті в стані Stopped.
  • Після onStop можливі два сценарії: onRestart (повернення на екран) або onDestroy (знищення Activity).
  • В onStop необхідно звільнити сенсори, анімації, камеру, location-слухачі — все, що не потрібне при невидимій Activity.
  • onStop відрізняється від onPause ступенем видимості: onPause — часткова, onStop — повна втрата видимості.
  • onSaveInstanceState викликається до onStop — використовуйте його для збереження транзитного UI-стану.
  • Корутини lifecycleScope з Dispatchers.IO — найкращий спосіб асинхронних операцій в onStop.
  • Завжди викликайте super.onStop() і обгортайте небезпечні операції в try-catch для уникнення Force Close.

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також