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 удаляется полностью. System UI может убить процесс приложения, находящегося в состоянии Stopped, при нехватке памяти — это так называемый process death. Разработчик обязан сохранить критичные данные (черновики, позицию скролла) в 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.
  • Входящий звонок — 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 рекомендует сохранять только transient UI-состояние — не данные репозитория или ViewModel, которые живут вне Activity.

Какие ресурсы освобождать в onStop

В onStop разработчик обязан освободить все ресурсы, которые не нужны, когда Activity не видна. Это снижает нагрузку на батарею, процессор и память, а также предотвращает ANR при возврате на активность.

Что освобождать в onStop:

  • Анимации и transitions — остановить ObjectAnimator, ValueAnimator, ViewPropertyAnimator. Работающая анимация невидимой Activity — пустая трата GPU-циклов.
  • Сенсоры (Sensors) — отписаться от SensorManager (акселерометр, гироскоп, магнетометр). Сенсоры потребляют энергию даже при скрытом Activity.
  • Камера и микрофон — освободить Camera2 или CameraX, остановить MediaRecorder. Оставлять камеру активной при скрытом Activity запрещено политикой Google Play.
  • LocationListener — отписаться от FusedLocationProviderClient или LocationManager. Геолокация — самый энергоёмкий ресурс.
  • Network listeners — закрыть WebSocket, отменить HTTP-запросы, которые не нужны в фоне.
  • MediaPlayer и ExoPlayer — поставить на паузу или остановить, если воспроизведение не должно продолжаться в фоне.

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

Отличие onStop от onPause

onPause и onStop различаются степенью потери видимости и объёмом обязательных действий. onPause вызывается при частичной потере фокуса (например, открытие диалогового окна или системного меню), onStop — при полной потере видимости. Это различие важно для выбора, какие ресурсы освобождать на каждом этапе.

ХарактеристикаonPauseonStop
Степень видимостиЧастично видимоПолностью невидимо
ФокусПотерянПотерян
Время выполненияДо 500 мсДо 5 с (ANR-таймаут)
Ресурсы к освобождениюКритичные (медиа, камера)Все невидимые (сенсоры, анимации, location)
Восстановление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 передаётся для восстановления состояния. Этот сценарий (process death) — одна из самых частых причин багов в 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", "Accel: 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, не блокируя main-поток.

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 — используйте его для сохранения transient UI-состояния.
  • Корутины lifecycleScope с Dispatchers.IO — предпочтительный способ асинхронных операций в onStop.
  • Всегда вызывайте super.onStop() и оборачивайте опасные операции в try-catch для избежания Force Close.

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

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