2

This question is about options menus inflated from Fragments into a Toolbar, via Fragment#setHasOptionsMenu(true).

Let’s say we have an activity with 3 fragments:

FragmentA
FragmentB (with menu)
FragmentC
    FragmentD (with menu)

Fragments A, B and C are part of the main activity, and are switched using FragmentTransaction#replace(). FragmentD is actually a child fragment of FragmentC. So, in FragmentC we do like:

getChildFragmentManager().beginTransaction().replace(R.id.container, new FragmentD());

First case: going to B, then back to A

All goes well: when in B, I see the overflow icon with my menu; back in A, the icon disappears.

Second case: going to C, then back to A

When in C, D is loaded and its menu is shown; back in A, the menu is still there! Why is this? Is this a bug? How should this be addressed in a pleasant way (e.g. not a dirty specific workaround that makes your code unreadable and unscalable)?

I can find a solution myself by trying a little bit, but I am mostly interested in why this happens.

Some code

Here’s a minimal example.

This might be a FragmentC that loads a FragmentD:

public class FragmentC extends Fragment {

    @Override
    public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if (savedInstanceState == null) {
            FragmentD f = new FragmentD();
            getChildFragmentManager()
                    .beginTransaction()
                    .replace(getContainerId(), f, “tag")
                    .addToBackStack(“tag")
                    .commit();
        }
    }
}

This might be a menu fragment, like both FragmentB and FragmentD:

public class MenuFragment extends Fragment {

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        setHasOptionsMenu(true);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        super.onCreateOptionsMenu(menu, inflater);
        inflater.inflate(R.menu.list_or_grid, menu);
    }
}

FragmentA can be whatever you want. The main activity switches through fragments using replace (adding to back stack, for what it’s worth):

// className can be FragmentA, FragmentB or FragmentC class names
private void goToFragment(String className) {
    FragmentManager f = getSupportFragmentManager();
    Fragment fragment = Fragment.instantiate(this, className);
    f.beginTransaction()
            .replace(R.id.fragment_content, fragment, className)
            .addToBackStack(className)
            .commit();
}
natario
  • 24,954
  • 17
  • 88
  • 158
  • @Yvette added some info. – natario Jun 18 '16 at 14:04
  • is onCreateOptionsMenu() ever called when coming back from D to A? – and_dev Jun 18 '16 at 14:05
  • @and_dev no, it just persists (even though both fragment C and D go through onDestroyView() ) – natario Jun 18 '16 at 14:12
  • @Yvette there’s a bottom bar in the outer activity with three buttons: A, B, C. On press of these buttons, goToFragment() is called. The issue stands either case, either I use a new instance of A or I pop the back stack, in A I will see the menu of D. And yes, D is added right when C is created. – natario Jun 18 '16 at 14:25
  • Might be worth mentioning that, if I go from C to **B**, which has a menu itself, I will see only B’s menu, and not B+D. Sorry if this is hard to follow. – natario Jun 18 '16 at 14:27
  • @Yvette even worse is that, if I set hasOptionsMenu(true) to A, even without inflating a real menu resource, it starts working correctly. I guess this is a scalable solution (calling setHasOptionsMenu in all my A’s), but I am still curious to why this happens. – natario Jun 18 '16 at 14:35

0 Answers0