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. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође