Activity Lifecycle — це набір методів зворотного виклику, які Android викликає при переході Activity між станами: створення, видимість, фокус введення, часткова втрата видимості, повне приховування та знищення. Система керує життєвим циклом кожного екрана застосунку, починаючи з моменту виклику onCreate() і закінчуючи onDestroy(). Розуміння цих станів є обов'язковою вимогою для стабільної роботи Android-застосунку, оскільки неправильна обробка переходів між методами призводить до витоків пам'яті, втрати даних користувача та неочікуваних збоїв. Докладніше про архітектуру Android читайте в загальній статті про Android.
Головне
Activity Lifecycle (життєвий цикл Activity) — це скінченний автомат станів, через який проходить кожен екран Android-застосунку від моменту створення до повного знищення. Система Android керує цим процесом на основі дій користувача: відкриття застосунку, згортання, поворот екрана, відповідь на вхідний дзвінок, перемикання між застосунками та завершення роботи.
Розуміння життєвого циклу необхідне кожному Android-розробнику, оскільки система може в будь-який момент знищити Activity при нестачі пам'яті — і застосунок повинен коректно відновити свій стан. Згідно з даними Google Android Vitals (2025), застосунки, які не обробляють збереження стану в onSaveInstanceState(), показують на 42% більше збоїв при перестворенні Activity.
Життєвий цикл включає шість основних методів-колбеків: onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy(). Додатково існує метод onRestart(), який викликається перед onStart(), коли Activity повертається із зупиненого стану. Кожен метод має суворо визначене призначення та час виконання — система викликає їх послідовно, і розробник може перевизначити будь-який з них для виконання власної логіки.
Цикл можна розділити на три ключові етапи: весь термін життя (onCreate → onDestroy), видимий термін життя (onStart → onStop) та термін життя на передньому плані (onResume → onPause). Розуміння цих трьох рівнів допомагає правильно розподілити код ініціалізації та звільнення ресурсів.
Кожен метод життєвого циклу виконує суворо визначене завдання. Система викликає їх у фіксованому порядку, і розробник повинен перевизначати тільки ті методи, які потрібні для конкретної логіки. Не рекомендується викликати методи життєвого циклу безпосередньо — цим займається Android Runtime.
Типова послідовність при запуску застосунку: onCreate → onStart → onResume. При натисканні кнопки «Назад»: onPause → onStop → onDestroy. При згортанні: onPause → onStop, потім при поверненні: onRestart → onStart → onResume.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onStart() {
super.onStart()
}
override fun onResume() {
super.onResume()
}
override fun onPause() {
super.onPause()
}
override fun onStop() {
super.onStop()
}
override fun onDestroy() {
super.onDestroy()
}
override fun onRestart() {
super.onRestart()
}
}
Кожен перевизначений метод зобов'язаний викликати super-версію — без цього система не зможе коректно завершити перехід між станами. Це правило закріплене в документації Android Developers і перевіряється lint-правилами Android Studio.
Перший рівень — весь термін життя (entire lifetime): проміжок між onCreate і onDestroy. Тут виконується одноразова ініціалізація та фінальне звільнення глобальних ресурсів. Другий рівень — видимий термін життя (visible lifetime): між onStart і onStop. Activity видна на екрані, але може бути частково перекрита іншим вікном. Третій рівень — термін життя на передньому плані (foreground lifetime): між onResume і onPause. Activity знаходиться на вершині стеку завдань і взаємодіє з користувачем.
onCreate() — перший і єдиний обов'язковий метод життєвого циклу Activity. Він викликається системою один раз при створенні екземпляра Activity. Цей метод приймає параметр savedInstanceState: Bundle?, який містить раніше збережений стан, якщо Activity перестворюється після знищення — наприклад, при повороті екрана.
Всередині onCreate виконуються такі завдання: ініціалізація користувацького інтерфейсу через setContentView() з передачею layout-ресурсу, прив'язка View-елементів через findViewById(), налаштування адаптерів для RecyclerView і ViewPager, відновлення стану з savedInstanceState, ініціалізація ViewModel і LiveData, налаштування слухачів кліків і жестів. Метод повинен завершитися якомога швидше — тривалі операції тут блокують відмальовування першого кадру, що збільшує час запуску застосунку.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
val userNameText: TextView = findViewById(R.id.user_name)
val loadButton: Button = findViewById(R.id.load_button)
if (savedInstanceState != null) {
userNameText.text = savedInstanceState.getString("user_name")
}
loadButton.setOnClickListener {
loadUserProfile()
}
}
Якщо Activity створюється вперше, savedInstanceState дорівнює null. При перестворенні після повороту екрана Bundle містить дані, збережені в onSaveInstanceState(). Перевірка на null — стандартна практика для коректного відновлення UI без втрати введених користувачем даних.
onStart() викликається одразу після onCreate() або після onRestart(), коли Activity стає видимою для користувача. У цьому стані Activity ще не знаходиться на передньому плані і не може взаємодіяти з користувачем, але її користувацький інтерфейс вже видно на екрані. Наприклад, при запуску застосунку система відмальовує перший кадр інтерфейсу між викликом onStart і onResume.
У методі onStart зазвичай виконуються такі дії: запуск анімацій, які повинні працювати, поки Activity видна; прив'язка широкомовних приймачів (BroadcastReceiver); підключення до служб геолокації та датчиків; оновлення даних з ViewModel або Room. Тут же виконується прив'язка до Bound-служб через bindService(), якщо застосунок використовує клієнт-серверну архітектуру всередині процесу.
override fun onStart() {
super.onStart()
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.requestLocationUpdates(
LocationManager.GPS_PROVIDER,
5000L,
10f,
locationListener
)
}
override fun onStop() {
super.onStop()
val locationManager = getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.removeUpdates(locationListener)
}
Важливе правило: ресурси, підключені в onStart, повинні звільнятися в onStop. Це гарантує, що коли Activity не видна на екрані, вона не споживає батарею та системні ресурси. Google Play Store перевіряє застосунки на витік LocationListener та інших системних служб при модерації оновлень.
onResume() — стан, у якому Activity знаходиться на передньому плані та готова до взаємодії з користувачем. Це робочий стан екрана: система передає Activity фокус введення, і всі події дотику, клавіатурного введення та жестів направляються цьому екрану. Метод onResume викликається щоразу, коли Activity повертається на передній план — після завершення іншої Activity, після закриття діалогового вікна, після розблокування пристрою.
В onResume виконують: відновлення анімацій, які були призупинені в onPause; відкриття камери та інших ексклюзивних ресурсів; реєстрацію сенсорних слухачів (акселерометр, гіроскоп); запуск таймерів і секундоміра для UI; оновлення вмісту екрана актуальними даними. У парі onResume / onPause працюють з ресурсами, які повинні бути активні тільки при фокусі — наприклад, безперервне розпізнавання мови або відеозахоплення.
override fun onResume() {
super.onResume()
cameraHolder.openCamera()
animator.resume()
sensorManager.registerListener(
stepCounter,
sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER),
SensorManager.SENSOR_DELAY_NORMAL
)
}
override fun onPause() {
super.onPause()
cameraHolder.closeCamera()
animator.pause()
sensorManager.unregisterListener(stepCounter)
}
Різниця між onStart і onResume суттєва: Activity може бути видима (onStart), але не активна (onResume) — наприклад, коли поверх неї відображається спливаюче діалогове вікно або прозорий екран блокування. Саме в onResume, а не в onStart, слід відкривати ексклюзивні ресурси, до яких потрібен монопольний доступ.
onPause() викликається, коли Activity втрачає фокус введення, але залишається частково видимою. Типові сценарії: відкриття діалогового вікна, натискання кнопки «Нещодавні застосунки», вхідний дзвінок, натискання кнопки «Додому» (у цьому випадку за onPause послідує onStop). Метод onPause — останнє надійне місце для збереження даних, які користувач не повинен втратити.
В onPause виконують: збереження чернеток листів і форм введення в Room або SharedPreferences; зупинка анімацій та відтворення відео; закриття камери та звільнення монопольних ресурсів; скасування дорогих операцій, не критичних для фону. Метод onPause повинен завершуватися за менш ніж 100 мілісекунд — система блокує перехід до наступної Activity, поки onPause не поверне керування, і перевищення ліміту призводить до ANR (Application Not Responding).
override fun onPause() {
super.onPause()
val editor = SharedPreferences.Manager ...
editor.putString("draft_text", draftEditText.text.toString())
editor.apply()
videoView.pause()
cameraHolder.release()
}
Важливо: onPause виконується в UI-потоці, тому будь-які блокуючі операції, такі як запис до бази даних через Room із синхронним запитом, повинні бути замінені на асинхронні (корутини) або виконуватися у фоновому потоці. Використовуйте apply() замість commit() для SharedPreferences — apply записує дані асинхронно і не блокує UI-потік.
onStop() викликається, коли Activity перестає бути видимою для користувача. Це відбувається в наступних випадках: Activity повністю перекрита іншою Activity; користувач натиснув кнопку «Додому» або переключився на інший застосунок; Activity завершується (буде викликаний потім onDestroy). У стані onStop Activity залишається в пам'яті та зберігає всі свої поля — вона не знищена, але й не активна.
В onStop виконують: відписку від BroadcastReceiver, зареєстрованих в onStart; відключення від Bound-служб; звільнення LocationListener, SensorListener та інших системних слухачів; зупинку тривалих фонових операцій, які не потрібні, коли застосунок приховано; запис поточного стану UI в Bundle через onSaveInstanceState(), якщо це не було зроблено в onPause.
override fun onStop() {
super.onStop()
unregisterReceiver(connectivityReceiver)
unbindService(serviceConnection)
if (isChangingConfigurations()) {
Log.d("Lifecycle", "Activity перестворюється через конфігурацію")
}
}
Система може знищити Activity у стані onStop без виклику onDestroy при нестачі пам'яті. Тому всі критичні дані повинні бути збережені до переходу в onStop. Прапорець isChangingConfigurations() дозволяє визначити, чи пов'язаний виклик onStop з поворотом екрана — у цьому випадку Activity буде перестворено, а не завершено.
onDestroy() — останній метод життєвого циклу, що викликається перед повним знищенням Activity. Система викликає onDestroy у двох випадках: Activity завершується викликом finish() або користувач натискає кнопку «Назад»; Activity знищується системою через зміну конфігурації (наприклад, поворот екрана) і буде створено заново. Метод onDestroy дозволяє виконати фінальне очищення ресурсів: відв'язку потоків і корутин, закриття постійно відкритих курсорів і сокетів, звільнення нативної пам'яті через NDK.
override fun onDestroy() {
super.onDestroy()
backgroundJob.cancel()
dbHelper.close()
if (isFinishing) {
Log.d("Lifecycle", "Activity завершується остаточно")
} else {
Log.d("Lifecycle", "Activity буде перестворено")
}
}
Важливе зауваження: в onDestroy не гарантується виклик, якщо процес застосунку вбито системою (out-of-memory kill). Тому покладатися на onDestroy для збереження даних не можна — це завдання вирішується в onPause або onStop. Властивість isFinishing дозволяє відрізнити завершення Activity за допомогою finish() від перестворення при зміні конфігурації.
onRestart() викликається перед onStart(), коли Activity повертається із зупиненого стану (onStop) назад на передній план. Це відбувається, коли користувач повторно відкриває застосунок з меню «Нещодавні» або повертається до Activity, натиснувши «Назад» у дочірньому екрані. Метод onRestart дозволяє виконати логіку, відмінну від onCreate, — наприклад, оновити дані, які могли змінитися, поки Activity було приховано.
override fun onRestart() {
super.onRestart()
refreshDataFromNetwork()
Log.d("Lifecycle", "Activity перезапускається зі стеку")
}
Типовий сценарій: користувач відкрив застосунок, переключився на інше завдання, а через годину повернувся. В onRestart застосунок може перевірити актуальність даних і, якщо минуло багато часу, запропонувати перезавантажити вміст. Це покращує користувацький досвід і знижує ймовірність показу застарілої інформації.
Поворот екрана — найчастіший сценарій перестворення Activity. За замовчуванням Android знищує поточну Activity і створює нову при кожній зміні орієнтації. Якщо не зберегти стан, користувач втратить усі введені дані. Для цього Android надає два механізми: onSaveInstanceState() для серіалізованих даних і ViewModel для даних, що переживають конфігураційні зміни.
onSaveInstanceState() викликається перед знищенням Activity для збереження тимчасового стану. Збережені дані передаються в onCreate через параметр savedInstanceState і в метод onRestoreInstanceState(), який викликається після onStart. Bundle має обмеження за розміром — близько 500 КБ, тому великі обсяги даних (наприклад, бітмапи) зберігають через ViewModel.
<!-- AndroidManifest.xml — фіксація орієнтації -->
<activity android:name=".MainActivity"
android:configChanges="orientation|screenSize" />
Фіксація орієнтації через android:configChanges запобігає перестворенню Activity, але вважається антипатерном, якщо застосунок повинен підтримувати обидві орієнтації. Сучасна рекомендація Google — використовувати ViewModel у зв'язці з onSaveInstanceState для даних, які користувач вводить в UI.
Fragment має власний життєвий цикл, схожий на Activity, але з додатковими методами: onAttach, onCreate, onCreateView, onViewCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach. Fragment завжди існує всередині Activity, і його життєвий цикл прив'язаний до життєвого циклу Activity-контейнера. Якщо Activity знищується, Fragment слідує за ним.
Основна відмінність: Fragment керує не тільки станом компонента, але й ієрархією View. Метод onCreateView повертає кореневий View фрагмента, а onDestroyView — знищує цю ієрархію. Це дозволяє Fragment переживати перестворення Activity при повороті екрана: Fragment зберігається, а його View створюється заново в onCreateView.
class ProfileFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
return inflater.inflate(R.layout.fragment_profile, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val avatarImage: ImageView = view.findViewById(R.id.avatar_image)
loadAvatar(avatarImage)
}
}
Розуміння різниці між onCreate і onCreateView критично важливе: onCreate викликається один раз за життя Fragment (навіть при перестворенні View), а onCreateView — щоразу, коли Fragment створює або перестворює свою ієрархію View. Ініціалізацію даних виконують в onCreate, а прив'язку UI — в onViewCreated.
LifecycleObserver — компонент бібліотеки Android Jetpack, який дозволяє реагувати на зміни життєвого циклу без перевизначення методів в Activity або Fragment. Замість того щоб дублювати код у кожному методі життєвого циклу, розробник створює окремий клас з анотаціями @OnLifecycleEvent і передає його в lifecycle.addObserver().
Jetpack також надає клас LifecycleOwner — інтерфейс, який реалізують AppCompatActivity і Fragment. Будь-який об'єкт, що реалізує LifecycleOwner, може керувати підписками LiveData, корутин через lifecycleScope і роботу WorkManager у прив'язці до життєвого циклу. Це наріжний камінь сучасної архітектури Android, заснованої на MVVM і Jetpack.
class MyLocationObserver(private val context: Context) : DefaultLifecycleObserver {
override fun onStart(owner: LifecycleOwner) {
startLocationUpdates()
}
override fun onStop(owner: LifecycleOwner) {
stopLocationUpdates()
}
}
// В Activity:
lifecycle.addObserver(MyLocationObserver(this))
Використання DefaultLifecycleObserver спрощує тестування, зменшує дублювання коду та робить логіку життєвого циклу перевикористовуваною між різними екранами. Це сучасна заміна ручному перевизначенню onStart/onStop у кожній Activity. В Android-застосунках, розроблених IT Sectr, ми застосовуємо LifecycleObserver для геолокації, Bluetooth-сканування та аналітики — це скорочує обсяг шаблонного коду на 30–40%.
Поширені запитання
Якщо не викликати super.onCreate() або будь-який інший super-метод життєвого циклу, система викине виняток SuperNotCalledException і застосунок впаде зі збоєм. Це жорстка вимога Android Runtime — кожен метод зобов'язаний делегувати виконання базовому класу, інакше внутрішній скінченний автомат не зможе перейти в наступний стан.
Activity перестворюється при повороті екрана, тому що зміна орієнтації — це зміна конфігурації пристрою (configuration change). За замовчуванням Android знищує Activity і створює нову, щоб завантажити альтернативні ресурси (layout-land, values-land). Щоб вимкнути перестворення, можна додати атрибут android:configChanges у маніфест, але Google рекомендує використовувати ViewModel для збереження даних.
Критичні дані зберігають в onPause(), оскільки це останній метод, який гарантовано викликається перед тим, як застосунок може бути вбито системою. Після onStop і onDestroy система може завершити процес без виклику додаткових методів. Для чернеток і проміжних даних використовуйте SharedPreferences з apply() або Room з корутинами.
onPause викликається, коли Activity втрачає фокус, але залишається частково видимою (наприклад, відкрито діалогове вікно). onStop викликається, коли Activity повністю прихована з екрана іншою Activity або натисканням кнопки «Додому». Основна практична відмінність: onPause — остання точка збереження даних, onStop — місце звільнення слухачів і системних служб, які не потрібні в фоні.
ViewModel — компонент Android Jetpack, який зберігає дані UI та автоматично переживає конфігураційні зміни (поворот екрана). ViewModel не знищується при перестворенні Activity: вона живе, поки LifecycleOwner (Activity або Fragment) не завершиться остаточно. Це вирішує проблему збереження даних при повороті екрана без використання Bundle та onSaveInstanceState. ViewModel — обов'язковий елемент архітектури MVVM, рекомендованої Google.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також