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 удаляется полностью. System UI может убить процесс приложения, находящегося в состоянии Stopped, при нехватке памяти — это так называемый process death. Разработчик обязан сохранить критичные данные (черновики, позицию скролла) в 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 рекомендует сохранять только transient UI-состояние — не данные репозитория или ViewModel, которые живут вне Activity.
В onStop разработчик обязан освободить все ресурсы, которые не нужны, когда Activity не видна. Это снижает нагрузку на батарею, процессор и память, а также предотвращает ANR при возврате на активность.
Что освобождать в onStop:
Чего не делать в onStop: Не выполняйте длительные операции — сохранение больших данных в БД, сетевые запросы, сложные вычисления. onStop выполняется на main-потоке и блокирует возврат на Activity. Для длительных операций используйте WorkManager с задержкой или корутины в viewModelScope. Не освобождайте ресурсы ViewModel — ViewModel переживает onStop и будет использована при возврате.
onPause и onStop различаются степенью потери видимости и объёмом обязательных действий. onPause вызывается при частичной потере фокуса (например, открытие диалогового окна или системного меню), onStop — при полной потере видимости. Это различие важно для выбора, какие ресурсы освобождать на каждом этапе.
| Характеристика | onPause | onStop |
|---|---|---|
| Степень видимости | Частично видимо | Полностью невидимо |
| Фокус | Потерян | Потерян |
| Время выполнения | До 500 мс | До 5 с (ANR-таймаут) |
| Ресурсы к освобождению | Критичные (медиа, камера) | Все невидимые (сенсоры, анимации, location) |
| Восстановление | 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 передаётся для восстановления состояния. Этот сценарий (process death) — одна из самых частых причин багов в 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", "Accel: 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, не блокируя main-поток.
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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также