Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicating menu items via different Fragments

After OnCreateOptionsMenu() marked as deprecated, I've managed to use new API from release notes https://developer.android.com/jetpack/androidx/releases/activity#1.4.0-alpha01 In my app user can switch Fragments via bottomNavigation. As I understand docs, in each Fragment I've implemented MenuProvider(with or without Lifecycle, doesn't matter for result). But now in each Fragment user have all items from all menuInflaters. There is the code of implementation

FRAGMENT A

@Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        SetMainParams();
        fragment = inflater.inflate( R.layout.fragment_A, container, false );

        addMenu();

        return fragment;
    }

    private void addMenu()
    {
        MenuProvider menuProvider = new MenuProvider()
        {
            @Override
            public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
            {
                menuInflater.inflate(R.menu.menu_fragment_A, menu);
            }

            @Override
            public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
            {
                if( menuItem.getItemId() == R.id.filters_prev )
                    filtersPrevious();
                else if( menuItem.getItemId() == R.id.filters )
                    showFilters();
                else
                    filtersNext();

                return false;
            }
        };

        requireActivity().addMenuProvider(menuProvider, getViewLifecycleOwner(), Lifecycle.State.RESUMED);
    }

FRAGMENT B

@Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        SetMainParams();
        binding = FragmentBBinding.inflate(inflater, container, false);
        fragment = binding.getRoot();
        init();

        addMenu();

        return fragment;
    }

    private void addMenu()
    {
        MenuProvider menuProvider = new MenuProvider()
        {
            @Override
            public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
            {
                menuInflater.inflate(R.menu.menu_fragment_B, menu);
                filtersMenu = menu.getItem(0);
            }

            @Override
            public boolean onMenuItemSelected(@NonNull MenuItem menuItem)
            {
                if( menuItem.getItemId() == R.id.filters )
                    loadFilters();

                return false;
            }
        };

        requireActivity().addMenuProvider(menuProvider, getViewLifecycleOwner(), Lifecycle.State.RESUMED);
    }

Switching from bottomNavigation

binding.bottomNav.setOnItemSelectedListener(item ->
        {
            int itemId = item.getItemId();

            if( itemId == R.id.A )
            {
                fm.beginTransaction().hide(active_fragment).show(A_fragment).commit();
                active_fragment = A_fragment;
                setWithElevation(false);
            }
            else if( itemId == R.id.B )
            {
                fm.beginTransaction().hide(active_fragment).show(B_fragment).commit();
                active_fragment = B_fragment;
                setWithElevation(true);
            }

            active_fragment.startFragment();
            active_fragment.setTitle();
            return true;
        });

        fm.beginTransaction().add( R.id.fl_content, A_fragment, "A_fragment" ).hide(A_fragment).commit();
        fm.beginTransaction().add( R.id.fl_content, B_fragment, "B_fragment" ).hide(B_fragment).commit();

Is there any ideas, why new API works like this, or maybe i've made a mistake. Thanks a lot for help :)

like image 278
Vsevolod Cheverda Avatar asked Nov 28 '25 12:11

Vsevolod Cheverda


1 Answers

I also experienced this problem today. So not sure if you have intellisense, but look at some of the Menu interface methods. I used the hasVisibleItems() method in Kotlin to only inflate the menu if it does not exist. Java also has the method; your snippet augmented with conditional:

MenuProvider menuProvider = new MenuProvider()
    {
         @Override
         public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater)
         {
             if (!menu.hasVisibleItem()) {  // only inflate if no items
                 menuInflater.inflate(R.menu.menu_fragment_A, menu);
             }
         }        
//...

Menu also has a bunch of other methods that may assist for specific items.
Also another good idea would be to use the MenuHost interface to keep track of your MenuProvider. I believe in Java; inside your Fragments; it would be along the lines of:

activityFragment = this.requireActivity();
Menuhost menuHost = (MenuHost) activityFragment;
menuHost.addMenuProvider(
    menuProvider,
    this.getViewLifecycleOwner(),
   State.RESUMED
);

Menu providers can then be invalidated ect.

like image 58
Hmerman6006 Avatar answered Nov 30 '25 01:11

Hmerman6006