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 включва 7 обратни връзки: 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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също