Fragment and view lifecycles

Lifecycle and app components Mid-level Kotlin 2.0+ API 24+ Reviewed By Best Latest Apps

Spot the bug

After returning from the back stack, every update is handled twice. Which line is the bug?

  1. class FeedFragment : Fragment() {
  2. private val vm: FeedViewModel by viewModels()
  3. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  4. lifecycleScope.launch {
  5. vm.items.collect { render(it) }
  6. }
  7. }
  8. }
Hint 1 of 1

Which lifecycle ends when the view is destroyed?

Choose an answer, then open Show answer below to check it.

Show answer
  • Answer: line 4 lifecycleScope.launch {

The Fragment's own lifecycleScope lives on while the view is destroyed, so a second collector is added when the view is recreated. Use viewLifecycleOwner.lifecycleScope with repeatOnLifecycle(STARTED).

30-second answer

A Fragment object can outlive its view: on the back stack, the Fragment stays alive while its view is destroyed and later recreated. So it has its own lifecycle and a separate viewLifecycleOwner. Anything that touches views, such as collecting UI state or binding, must use viewLifecycleOwner, or it keeps a reference to a dead view and may observe twice.

Practise saying it · 35 s. No recording, just a timer

Explain the Fragment's two lifecycles.

Say your answer out loud, then check which of these points you covered:

  • Fragment can outlive its view
  • Use viewLifecycleOwner for UI work
  • Clear binding in onDestroyView
  • Fragment Result API for results

Deep dive

onCreateView/onViewCreated and onDestroyView bound the view lifecycle.

Clear the view binding in onDestroyView to avoid leaking the view hierarchy.

Use viewLifecycleOwner.lifecycleScope with repeatOnLifecycle(STARTED) for collecting.

Pass results between Fragments with the Fragment Result API or a shared ViewModel, not by calling methods on each other.

The ViewModel used above Compile-checked · Kotlin 2.4.21
class FeedViewModel : ViewModel() {
    val items: StateFlow<List<String>> = MutableStateFlow(emptyList())
}

Common mistakes

  • Collecting with the Fragment's own lifecycleScope in onViewCreated, so a second collector is added when the view is recreated.
  • Keeping a binding reference after onDestroyView.
  • Using setTargetFragment, which is deprecated.

Senior take & follow-ups

Draw the two timelines, and give the double-collector bug as proof you've hit it.

Follow-up questions

Think of your answer first, then open the hint.

  1. How do you return a result to the previous Fragment?

    Show hint

    setFragmentResult / setFragmentResultListener, or a shared ViewModel.

  2. Why clear the binding?

    Show hint

    The Fragment lives on the back stack while its view is gone; the binding holds the old views.

Suggest a fix if something here is wrong or out of date.