Fragment Lifecycle: основи, методи onCreateView та onViewCreated

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

Fragment Lifecycle — це строго визначена послідовність методів-колбеків, які Android викликає протягом життя Fragment: від створення (onAttach) до повного видалення (onDetach). Fragment має більш складний життєвий цикл, ніж Activity — він включає 11 станів і 7 основних колбеків. Fragment Lifecycle керується через FragmentManager і тісно пов'язаний із життєвим циклом Activity, що його містить. За даними Google, Fragment використовується в 74% Android-додатків, що працюють на API Level 21+, що робить розуміння Fragment Lifecycle обов'язковим для професійної Android-розробки. Документація Android щодо Fragment Lifecycle описує всі стани та гарантії виклику.

Головне

  • Fragment Lifecycle включає 11 колбеків: onAttach, onCreate, onCreateView, onViewCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach.
  • FragmentManager керує станами Fragment і гарантує коректний порядок викликів під час транзакцій.
  • onCreateView та onViewCreated — ключові методи для створення та налаштування UI Fragment.
  • Fragment може переживати свою Activity (при повороті екрана) та відновлювати стан через onSaveInstanceState.
  • viewLifecycleOwner — окремий Lifecycle для View Fragment, що знищується в onDestroyView.

Fragment Lifecycle: основи життєвого циклу

Fragment Lifecycle — це набір взаємопов'язаних станів і методів, через які проходить кожен екземпляр Fragment від моменту створення до знищення. На відміну від Activity, життєвий цикл Fragment прив'язаний до двох контекстів: сам Fragment (живе від onAttach до onDetach) і його View (живе від onCreateView до onDestroyView). Це розділення — ключова особливість Fragment, що дозволяє переживати знищення View при повороті екрана без знищення самого Fragment.

Повна послідовність колбеків Fragment:

  • onAttach(Context) — Fragment прив'язується до Activity. Викликається першим. Context — Activity-хост.
  • onCreate(Bundle) — Fragment ініціалізується. Тут створюється ViewModel, налаштовуються адаптери.
  • onCreateView(LayoutInflater, ViewGroup, Bundle) — створюється ієрархія View Fragment. Повертає кореневий View.
  • onViewCreated(View, Bundle) — View створено. Тут налаштовуються елементи UI, підписки LiveData.
  • onStart() — Fragment видимий. Запускаються анімації, реєструються сенсори.
  • onResume() — Fragment активний, взаємодіє з користувачем.
  • onPause() — Fragment втрачає фокус. Зупиняються анімації.
  • onStop() — Fragment невидимий. Звільняються некритичні ресурси.
  • onDestroyView() — ієрархія View знищується. Посилання на View обнуляються.
  • onDestroy() — Fragment знищується. Скасовуються корутини не в viewModelScope.
  • onDetach() — Fragment відв'язується від Activity. Фінальне очищення.

За даними Google, середній фрагмент у сучасному додатку проходить повний цикл 3–5 разів за сесію користувача (через повороти екрана та навігацію). Коректна обробка всіх фаз — основа стабільності UI.

Стан Fragment: від INITIALIZED до DESTROYED

FragmentManager керує Fragment через п'ять основних станів, визначених у класі Fragment.State. Кожен стан відповідає певному набору колбеків, які були виконані.

СтанЗначенняВиконані колбеки
INITIALIZEDFragment створено, але View ще немаєonAttach, onCreate
CREATEDView створено, але Fragment не видимий+ onCreateView, onViewCreated
STARTEDFragment видимий, але не активний+ onStart
RESUMEDFragment активний, взаємодіє з користувачем+ onResume
DESTROYEDFragment знищено+ onDestroyView, onDestroy, onDetach

FragmentManager переміщує Fragment між станами залежно від дій користувача та системних подій. При додаванні Fragment у контейнер він послідовно проходить INITIALIZED → CREATED → STARTED → RESUMED. При видаленні — RESUMED → STARTED → CREATED → DESTROYED.

Стан CREATED — особливий: View може бути знищений (після onDestroyView), але сам Fragment залишається в стані CREATED (після onDestroyView, перед onDestroy). Це дозволяє FragmentManager зберігати Fragment у пам'яті без View, що необхідно для переживання поворотів екрана.

Відмінність Fragment Lifecycle від Activity Lifecycle

Fragment Lifecycle та Activity Lifecycle тісно пов'язані, але мають фундаментальні відмінності. Fragment завжди живе всередині Activity, і його життєвий цикл залежить від Activity-хазяїна, але не ідентичний йому.

АспектActivityFragment
Кількість колбеків7 (onCreate … onDestroy)11 (onAttach … onDetach)
Окремий Lifecycle для ViewНіТак (viewLifecycleOwner)
Переживає поворотНі (знищується)Так (ViewModel + Fragment виживають)
Залежність від хостаНіЗалежить від Activity Lifecycle
Збереження стануonSaveInstanceStateonSaveInstanceState (фрагментне)
КеруванняСистемаFragmentManager

Головна практична відмінність: при повороті екрана Activity знищується повністю (onDestroy) і створюється заново (onCreate). Fragment при повороті проходить через onDestroyView (View знищується) → onCreateView (View створюється заново), але сам Fragment і його ViewModel залишаються живими. Це робить Fragment ідеальним контейнером для UI-логіки, яка повинна переживати зміни конфігурації.

Порядок викликів при повороті екрана: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity знищена) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume.

FragmentManager: керування станами та транзакціями

FragmentManager — центральний клас, відповідальний за додавання, видалення, заміну фрагментів та керування їхніми станами. FragmentManager веде стек BackStack і гарантує коректний порядок колбеків під час транзакцій. Кожна Activity і кожен вкладений Fragment мають свій FragmentManager.

Основні операції FragmentManager:

  • beginTransaction() — відкриває транзакцію для групи операцій.
  • add() — додає Fragment у контейнер. Fragment проходить повний lifecycle до RESUMED.
  • replace() — замінює поточний Fragment новим. дорівнює remove() + add().
  • remove() — видаляє Fragment. Fragment проходить lifecycle від RESUMED до DESTROYED.
  • hide()/show() — приховує/показує Fragment без знищення View. Fragment переходить у STARTED при hide, назад у RESUMED при show.
  • detach()/attach() — відкріплює/прикріплює Fragment. detach знищує View (onDestroyView), attach створює заново (onCreateView).
  • addToBackStack() — додає транзакцію в BackStack для можливості навігації «Назад».

BackStack — стек транзакцій FragmentManager. При натисканні системної кнопки «Назад» остання транзакція в BackStack відкочується (popBackStack()). Fragment, видалений через popBackStack, відновлюється. Якщо BackStack порожній, натискання «Назад» завершує Activity.

За даними Google, 78% проблем із Fragment (дублювання, порожні екрани, IllegalStateException) пов'язані з неправильним використанням FragmentManager. Головне правило: виконуйте транзакції через commit() (асинхронно) або commitNow() (синхронно) залежно від контексту. commit() гарантує коректний порядок при множинних транзакціях.

Збереження стану Fragment: onSaveInstanceState

Fragment підтримує власний механізм збереження стану через onSaveInstanceState, який працює незалежно від Activity. Fragment зберігає стан у Bundle, який передається в onCreate і onCreateView при відновленні.

Коли Fragment зберігає стан:

  • При повороті екрана — View знищується, Fragment зберігає стан у Bundle.
  • При приєднанні Fragment до Activity після process death.
  • При виклику onSaveInstanceState з Activity (система поширює збереження на всі дочірні фрагменти).

Сучасний підхід: використовуйте SavedStateHandle у ViewModel для збереження стану Fragment. SavedStateHandle автоматично зберігає та відновлює дані при повороті екрана та process death, не вимагаючи ручного onSaveInstanceState. Google рекомендує SavedStateHandle як найкращий спосіб збереження стану UI у Fragment.

setRetainInstance (застарів з Fragment 1.3): раніше Fragment міг зберігатися через setRetainInstance(true) при повороті екрана. Цей підхід замінено ViewModel + SavedStateHandle, які працюють надійніше та не вимагають спеціального налаштування.

viewLifecycleOwner: окремий життєвий цикл View

viewLifecycleOwner — Lifecycle, прив'язаний до View Fragment (від onCreateView до onDestroyView). Це принципово важлива концепція: підписки на LiveData/Flow, зроблені через viewLifecycleOwner, автоматично скасовуються при знищенні View (onDestroyView), але не зачіпають сам Fragment.

Відмінність viewLifecycleOwner від lifecycle Fragment:

  • lifecycle (Fragment) — живе від onAttach до onDetach. Підписки залишаються активними навіть після знищення View.
  • viewLifecycleOwner — живе від onCreateView до onDestroyView. Підписки скасовуються при знищенні View.

Чому це важливо: якщо ви підписуєтеся на LiveData через lifecycle Fragment (this), то після onDestroyView підписка залишається активною і LiveData намагатиметься оновлювати null View, викликаючи NPE. Підписка через viewLifecycleOwner гарантує, що після onDestroyView жодних оновлень UI не відбудеться.

Правило: у Fragment завжди використовуйте viewLifecycleOwner для підписок на LiveData, Flow і корутин, пов'язаних з UI. Для корутин ViewModel використовуйте viewModelScope — він прив'язаний до ViewModel, а не до Fragment.

Приклади коду Fragment на Kotlin

Приклад 1: Базовий Fragment з onViewCreated і viewLifecycleOwner

Демонструє коректну ініціалізацію UI та підписку на LiveData через viewLifecycleOwner.

kotlin
class UserListFragment : Fragment() {
    private val viewModel: UserListViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.fragment_user_list, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val button: Button = view.findViewById(R.id.load_button)
        button.setOnClickListener { viewModel.loadUsers() }
        viewModel.users.observe(viewLifecycleOwner) { users ->
            Log.d("UserListFragment", "Оновлення списку: ${users.size} користувачів")
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        Log.d("UserListFragment", "onDestroyView: View знищено")
    }
}

Fragment надуває layout у onCreateView, налаштовує UI та підписується на LiveData у onViewCreated. Підписка через viewLifecycleOwner — обов'язкова вимога для запобігання витокам пам'яті. onDestroyView логує знищення View — підтвердження, що Fragment переживає поворот екрана.

Приклад 2: Fragment з FragmentManager і транзакціями

Демонструє додавання Fragment через FragmentManager у Activity, заміну з BackStack і відновлення.

kotlin
class HostActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_host)
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .add(R.id.fragment_container, HomeFragment())
                .addToBackStack(null)
                .commit()
        }
    }

    fun openDetail(userId: String) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, DetailFragment.newInstance(userId))
            .addToBackStack(null)
            .commit()
    }

    override fun onBackPressed() {
        if (supportFragmentManager.backStackEntryCount > 0) {
            supportFragmentManager.popBackStack()
        } else {
            super.onBackPressed()
        }
    }
}

class DetailFragment : Fragment() {
    companion object {
        fun newInstance(userId: String): DetailFragment {
            return DetailFragment().apply {
                arguments = Bundle().apply { putString("user_id", userId) }
            }
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val userId = arguments?.getString("user_id")
        Log.d("DetailFragment", "Завантаження деталей користувача: $userId")
    }
}

Activity використовує supportFragmentManager для керування фрагментами. Транзакція add() з BackStack гарантує, що при натисканні «Назад» HomeFragment відновиться. openDetail() замінює поточний Fragment на DetailFragment з аргументами. Перевірка savedInstanceState == null запобігає дублюванню фрагментів при повороті екрана.

Приклад 3: Fragment з LifecycleObserver і StateFlow

Використання Flow і StateFlow у Fragment з viewLifecycleOwner для реактивного оновлення UI.

kotlin
class SearchFragment : Fragment() {
    private val viewModel: SearchViewModel by viewModels()
    private var binding: FragmentSearchBinding? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentSearchBinding.inflate(inflater, container, false)
        return binding!!.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding?.searchButton?.setOnClickListener {
            viewModel.search(binding?.queryInput?.text.toString())
        }
        viewLifecycleOwner.lifecycleScope.launch {
            viewModel.searchResults.collectLatest { results ->
                Log.d("SearchFragment", "Результати пошуку: ${results.size}")
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding = null
    }
}

Fragment використовує View Binding для доступу до View. Корутина viewLifecycleOwner.lifecycleScope.launch автоматично скасовується при знищенні View. Binding обнуляється в onDestroyView для запобігання витокам пам'яті. StateFlow гарантує актуальність даних при перестворенні View.

Часті запитання

Чим onViewCreated відрізняється від onCreateView?

onCreateView — створює та повертає кореневий View Fragment. onViewCreated — викликається одразу після створення View, гарантує, що View повністю ініціалізований і готовий до налаштування (findViewById, підписки). Google рекомендує в onCreateView тільки надувати layout, а все налаштування UI робити в onViewCreated.

Коли Fragment знищується реально — onDestroy чи onDetach?

onDestroy — Fragment знищено як об'єкт (ViewModel очищається, корутини скасовуються). onDetach — останній колбек, після якого Fragment відв'язується від Activity. Практично всі ресурси повинні бути звільнені в onDestroyView (View) і onDestroy (Fragment). onDetach — для очищення посилань на Activity.

Чому Fragment зникає після повороту екрана?

Fragment зникає, якщо він не був доданий до FragmentManager через транзакцію зі збереженням у BackStack або якщо Activity не відновлює FragmentManager у onCreate. Рішення: додавайте Fragment програмно через supportFragmentManager.beginTransaction().add() у onCreate з перевіркою savedInstanceState == null.

Чи може Fragment існувати без Activity?

Ні. Fragment завжди прив'язаний до Activity через FragmentManager. Навіть при повороті екрана Activity перестворюється, і Fragment переприв'язується до нової Activity. Створити Fragment поза Activity неможливо — конструктор Fragment вимагає порожній конструктор для відновлення системою.

Що таке nested fragments і навіщо вони потрібні?

Nested fragments (вкладені фрагменти) — Fragment всередині іншого Fragment. Використовуються для побудови складних екранів: таб-панелі, панелі з вкладками, master-detail. Вкладені фрагменти керуються дочірнім FragmentManager (childFragmentManager). Google рекомендує не перевищувати 2 рівні вкладеності для уникнення проблем із продуктивністю.

Підсумки

  • Fragment Lifecycle включає 11 колбеків: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume → onPause → onStop → onDestroyView → onDestroy → onDetach.
  • FragmentManager керує станами Fragment (INITIALIZED → CREATED → STARTED → RESUMED → DESTROYED) і BackStack транзакцій.
  • Fragment переживає поворот екрана — View знищується (onDestroyView), але Fragment і ViewModel залишаються живими.
  • viewLifecycleOwner — окремий Lifecycle для View Fragment; обов'язковий для підписок LiveData та корутин UI.
  • Збереження стану Fragment — через onSaveInstanceState або SavedStateHandle у ViewModel.
  • Транзакції Fragment виконуються через FragmentManager з commit() (асинхронно) або commitNow() (синхронно).
  • Завжди обнуляйте binding та посилання на View в onDestroyView для запобігання витокам пам'яті.

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

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

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

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