Home > OS >  How can I prevent options menu icons flickering in the action bar when switching between fragments?
How can I prevent options menu icons flickering in the action bar when switching between fragments?

Time:08-27

I am trying to migrate from the deprecated setHasOptionsMenu()/onCreateOptionsMenu() methods to the new addMenuProvider()/onCreateMenu() methods in order to show an options menu from a fragment. Using the new API, I get an ugly delay/flicker of the icons in the action bar when navigating between two fragments that both implement MenuProvider.

I assume this is caused by asynchronous lifecycle callbacks: the new fragment's menu is probably inflated and added just before the old fragment's Lifecycle.Event.ON_DESTROY event triggers the removal of the old menu items, causing a brief moment when both menus are active simultaneously. However, I can't figure out how to avoid this behavior. I have tried calling both removeMenuProvider() and invalidateOptionsMenu() from onDestroyView() in each fragment with no success. I also tried moving addMenuProvider() to onViewCreated() instead of onCreateView(). The issue does not occur with the old setHasOptionsMenu() API.

Minimal reconstruction:

  1. Open Android Studio, create a new project, and select the "Bottom Navigation Activity" template.
  2. Create two menu resource files, each containing at least one menu item with an icon and app:showAsAction="always".
  3. In two of the fragments shown by the bottom navigation controller, call the following from within onCreateView():
requireActivity().addMenuProvider(object: MenuProvider {
    override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
        menuInflater.inflate(/* one of the menus from step 2 */, menu)
    }

    override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
        return false
    }
}, viewLifecycleOwner)
  1. Run the app and switch between these fragments using the bottom navigation bar. You should see something like this: example gif.

CodePudding user response:

Got the answer from some nice people on the Buganizer: see https://issuetracker.google.com/issues/243679672.

In short, use addMenuProvider(/* provider */, viewLifecycleOwner, Lifecycle.State.RESUMED)

Using addMenuProvider(/* provider */, viewLifecycleOwner, Lifecycle.State.STARTED) seems to prevent a brief moment where no menu icons are visible (while also preventing overlap of the menus), though this seemingly contradicts the lifecycle state transitions that occur during animation as described in the link above...

  • Related