Android Development
Fragments
onCreateOptionsMenu
Android Menus
Mobile App Development

onCreateOptionsMenu inside Fragments

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Fragments can contribute menu items, but they do not participate in the activity menu automatically. The exact setup depends on whether you use the older fragment menu callbacks or the newer MenuHost and MenuProvider APIs, which are usually the cleaner lifecycle-aware approach in modern Android code.

The Classic Fragment Menu Pattern

In the older style, the fragment must opt in by calling setHasOptionsMenu(true).

kotlin
1class ItemsFragment : Fragment(R.layout.fragment_items) {
2
3    override fun onCreate(savedInstanceState: Bundle?) {
4        super.onCreate(savedInstanceState)
5        setHasOptionsMenu(true)
6    }
7
8    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
9        inflater.inflate(R.menu.items_menu, menu)
10        super.onCreateOptionsMenu(menu, inflater)
11    }
12
13    override fun onOptionsItemSelected(item: MenuItem): Boolean {
14        return when (item.itemId) {
15            R.id.action_refresh -> {
16                reloadData()
17                true
18            }
19            else -> super.onOptionsItemSelected(item)
20        }
21    }
22
23    private fun reloadData() {}
24}

Without setHasOptionsMenu(true), onCreateOptionsMenu inside the fragment will not be called.

The Modern MenuHost Approach

AndroidX introduced MenuHost and MenuProvider, which are usually a better fit for fragments because they are tied to lifecycle owners more explicitly.

kotlin
1class ItemsFragment : Fragment(R.layout.fragment_items) {
2    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
3        val menuHost: MenuHost = requireActivity()
4        menuHost.addMenuProvider(object : MenuProvider {
5            override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
6                menuInflater.inflate(R.menu.items_menu, menu)
7            }
8
9            override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
10                return when (menuItem.itemId) {
11                    R.id.action_refresh -> {
12                        reloadData()
13                        true
14                    }
15                    else -> false
16                }
17            }
18        }, viewLifecycleOwner, Lifecycle.State.RESUMED)
19    }
20
21    private fun reloadData() {}
22}

This is often safer because the menu provider is scoped to the fragment view lifecycle rather than lingering after the view is destroyed.

Why Lifecycle Scope Matters

Fragments can have their views destroyed and recreated while the fragment object still exists. If menu handling is not tied to viewLifecycleOwner or another correct lifecycle boundary, stale callbacks can remain registered and cause duplicated or confusing menu behavior.

That is one reason the modern API is generally preferred.

Multiple Fragments and Menu Conflicts

In multi-fragment screens, more than one fragment may try to contribute actions. Keep menu item IDs distinct and be clear about which fragment should own which actions. If the toolbar really belongs to a child fragment rather than the activity, it may be cleaner to inflate and handle the menu directly on that fragment-owned toolbar.

This ownership question matters more than many developers expect. A lot of menu bugs come from unclear architecture rather than incorrect callback syntax, especially when navigation, nested fragments, and a shared activity toolbar all interact.

Once menu ownership is explicit, the API choice usually becomes obvious as well. Fragment-scoped menu actions work best when their lifecycle follows the fragment’s visible UI state instead of the host activity’s longer lifetime.

That alignment is what prevents stale or duplicated actions after navigation and view recreation.

Common Pitfalls

  • Overriding onCreateOptionsMenu in a fragment without enabling menu participation first in the legacy API.
  • Registering menu behavior against the wrong lifecycle, so callbacks survive longer than the fragment view.
  • Letting multiple fragments contribute conflicting menu items with overlapping IDs.
  • Assuming the activity will automatically route all menu events the way the fragment expects.
  • Using the old pattern in new code when a lifecycle-aware MenuProvider would be simpler.

Summary

  • Fragments do not participate in the options menu automatically.
  • In the classic API, call setHasOptionsMenu(true) and override the menu callbacks.
  • In modern Android code, prefer MenuHost and MenuProvider for lifecycle-aware menu handling.
  • Scope menu registration carefully to avoid stale callbacks after view recreation.
  • Treat menu ownership as part of fragment architecture, not just a callback detail.

Course illustration
Course illustration

All Rights Reserved.