OnCreateOptionsMenu() not called in Fragment

AndroidAndroid Fragments

Android Problem Overview


I have an app which got one activity with 2 fragments placed horizontally.

In my activity I inflated menu using onCreateOptionsMenu() using which I am able to display actionbar options menu. But when I try to update the action bar menu items from one of my fragment, the onCreateoptionsmenu() is not called. So, I'm not able to update the action bar options menu.

The code in my activity is as below:

myActivity.java

package com.andr.androidtablelist;

import java.io.IOException;

import android.app.ActionBar;
import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;

import com.andr.fragments.ListLeftFragment;
import com.andr.utils.DBHelper;

      public class TabletActivity extends Activity {
	ActionBar actionBar = null;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		DBHelper dbhelper;
		dbhelper = new DBHelper(this);
		try {
			dbhelper.createDatabase();
		} catch (IOException ex) {
			ex.printStackTrace();
		}
		setContentView(R.layout.activity_tablet);
		actionBar = getActionBar();
		actionBar.setDisplayHomeAsUpEnabled(false);
		getFragmentManager().beginTransaction()
				.replace(R.id.master, ListLeftFragment.newInstance()).commit();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.tablet, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case android.R.id.home:
			Toast.makeText(
					getApplicationContext(),
					"Back Stack Count::"
							+ getFragmentManager().getBackStackEntryCount(),
					Toast.LENGTH_LONG).show();
			if (getFragmentManager().getBackStackEntryCount() == 1) {
				actionBar.setDisplayHomeAsUpEnabled(false);
			}
			if (getFragmentManager().getBackStackEntryCount() > 1) {
				getFragmentManager().popBackStack();

			}
			return true;

		}
		return super.onOptionsItemSelected(item);
	}

}
      // http://www.vogella.com/articles/AndroidListView/article.html

myFragment.java

      package com.andr.fragments;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Fragment;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.TextView;

import com.andr.androidtablelist.R;
import com.andr.helper.LazyHelper;

   public class ListLeftFragment extends Fragment{
	private static ListLeftFragment listFragment = null;
	
	public static ListLeftFragment newInstance(){
		listFragment = new ListLeftFragment();		
		return listFragment;
	}

	 @Override
	public void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		
		
	}
	 
	 @Override
	public View onCreateView(LayoutInflater inflater, ViewGroup container,
			Bundle savedInstanceState) {
		 View v =  inflater.inflate(R.layout.fragment_listlayout, container,false);
		 getActivity().invalidateOptionsMenu();
		 ListView lv = (ListView)v.findViewById(R.id.lview);
		 String[] values = new String[] { "Android", "iPhone", "WindowsMobile",
			        "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X",
			        "Linux", "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux",
			        "OS/2", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2",
			        "Android", "iPhone", "WindowsMobile" };
		 getActivity().getActionBar().setTitle("LeftList");
		 
		  ArrayList<String> list = new ArrayList<String>();
		 LazyHelper lHelper = new LazyHelper(getActivity());
		 list = lHelper.getLazyDetials();
		 
		   /* for (int i = 0; i < values.length; ++i) {
		      list.add(values[i]);
		    }
		    final StableArrayAdapter adapter = new StableArrayAdapter(getActivity(),
		        android.R.layout.simple_list_item_1, list);*/
		    LeftListAdapter lAdapter = new LeftListAdapter(getActivity(),list);
		    lv.setAdapter(lAdapter);
		    lv.setOnItemClickListener(new OnItemClickListener()
		    {

				@Override
				public void onItemClick(AdapterView<?> arg0, View arg1,
						int pos, long arg3) {
					final String clickedData = (String)arg0.getItemAtPosition(pos);
					Bundle bundle = new Bundle();
					bundle.putString("clickedItemName", clickedData);
					Fragment detailFragment = DetailFormRightFragment.newInstance();
					detailFragment.setArguments(bundle);
					getActivity().getFragmentManager().beginTransaction().replace(R.id.details, detailFragment).addToBackStack(null).commit();
				}
		    	
		    }
		    		);
		 return v;
	}
	 
	 
	 @Override
	public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
		super.onCreateOptionsMenu(menu, inflater);
		getActivity().getMenuInflater().inflate(R.menu.search, menu);
		SearchView searchView=(SearchView)menu.findItem(R.id.search);
		searchView.setIconifiedByDefault(true);
	} 
	 
	 @Override
	public boolean onOptionsItemSelected(MenuItem item) {
		
		 super.onOptionsItemSelected(item);
		 return false;
	}
	 
	 
	 @Override
	public void onPrepareOptionsMenu(Menu menu) {
		 super.onPrepareOptionsMenu(menu);
		/*MenuItem item;
		menu.clear();
		getActivity().getMenuInflater().inflate(R.menu.search, menu);
		SearchView searchView=(SearchView)menu.findItem(R.id.search);
		searchView.setIconifiedByDefault(true);*/
	}
	
	 private class StableArrayAdapter extends ArrayAdapter<String> {

		    HashMap<String, Integer> mIdMap = new HashMap<String, Integer>();

		    public StableArrayAdapter(Context context, int textViewResourceId,
		        List<String> objects) {
		      super(context, textViewResourceId, objects);
		      for (int i = 0; i < objects.size(); ++i) {
		        mIdMap.put(objects.get(i), i);
		      }
		    }

		    @Override
		    public long getItemId(int position) {
		      String item = getItem(position);
		      return mIdMap.get(item);
		    }

		    @Override
		    public boolean hasStableIds() {
		      return true;
		    }

		  }
	 
	 private class LeftListAdapter extends BaseAdapter implements OnClickListener {
		 private Context mcontext;
		 ArrayList<String> listData;
		 private  LayoutInflater inflater=null;
		 public LeftListAdapter(Context context, ArrayList<String> listItems) {
			  mcontext=context;
			  listData=listItems;
			  inflater = (LayoutInflater)mcontext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		 }
		 
		@Override
		public int getCount() {
			return listData.size();
		}

		@Override
		public Object getItem(int arg0) {
			return null;
		}

		@Override
		public long getItemId(int arg0) {
			// TODO Auto-generated method stub
			return 0;
		}

		@Override
		public View getView(int position, View view, ViewGroup arg2) {
			// create a ViewHolder reference
			View vi=view;
			if(vi==null){
				vi = inflater.inflate(R.layout.item, null);
			}
			TextView text=(TextView)vi.findViewById(R.id.text);
			text.setText(listData.get(position));
			vi.setOnClickListener(this);
			return vi;
		}

		@Override
		public void onClick(View vi) {
			TextView text=(TextView)vi.findViewById(R.id.text);
			Bundle bundle = new Bundle();
			bundle.putString("clickedItemName", text.getText().toString());
			Fragment detailFragment = DetailFormRightFragment.newInstance();
			detailFragment.setArguments(bundle);
			getActivity().getFragmentManager().beginTransaction().replace(R.id.details, detailFragment).addToBackStack(null).commit();			
		}
		 
	 }
   }

Android Solutions


Solution 1 - Android

In your fragment's onCreateView() method, you need to call setHasOptionsMenu(true) to tell the host activity that your fragment has menu options that it wants to add.

Solution 2 - Android

If you are using a theme that does not support ActionBar, then OnCreateOptionsMenu() will not be called automatically, even you wrote all Java codes properly.

You can open AndroidManifest.xml, change the value of android:theme to "@android:style/Theme.Holo.Light.DarkActionBar", or any other themes that support ActionBar.

Solution 3 - Android

this worked for me

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
		Bundle savedInstanceState) {

	setHasOptionsMenu(true);
	View view = inflater.inflate(R.layout.sample, null);
}

Solution 4 - Android

Also, make sure that the Toolbar instance you're passing to

setSupportActionBar(toolbar);

in your Activity is not null, because you won't get an exception if it is indeed null and you will lose a couple of hours like I did.

I used ButterKnife to bind the views, but accidentally placed setSupportActionBar(toolbar) before I actually made the call to ButterKnife.bind()

Solution 5 - Android

Simply tell the host activity that your fragment has options menu in its constructor.

public YourFragment() {setHasOptionsMenu(true);}

Although it worked for me, it is discouraged as noted in comment from @aldorain

> Applications should generally not implement a constructor. The first > place application code can run where the fragment is ready to be used > is in onAttach(Activity), the point where the fragment is actually > associated with its activity.

So put setHasOptionsMenu(true) in onCreateView() or onAttach() instead.

Solution 6 - Android

I you have a theme that doesn't provide you an AppBar by default and you are using a toolbar view to provide this feature instead, DON'T FORGET TO call setSupportActionBar(toolbar) in the onCreate() method of the activity that hosts your fragments.

After that call setHasOptionsMenu(true) in your onCreate() fragment method.

:)

Solution 7 - Android

When using the Navigation Architecture Component the action bar is not set so it needs to be done manually:

@Override
public void onViewCreated( @NonNull View view, @Nullable Bundle savedInstanceState ) {
	NavController navController = Navigation.findNavController( view );

	AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder( R.id.nav_1, R.id.nav_2, R.id.nav_3 ).build();

	Toolbar toolbar = view.findViewById( R.id.toolbar );
	((AppCompatActivity) requireActivity()).setSupportActionBar( toolbar );
	CollapsingToolbarLayout collapsingToolbarLayout = view.findViewById( R.id.collapsing_toolbar );

	NavigationUI.setupWithNavController( collapsingToolbarLayout, toolbar, navController, appBarConfiguration );
}

Solution 8 - Android

This one will have diminishing returns as time marches on. In my case it was an androidX dependency on androidx.fragment:fragment:1.3.0-alpha06 which had this bug

simply updating that to a stable version resolved the issue.

Solution 9 - Android

For those who have the NoActionBar theme such as: Theme.MaterialComponents.Light.NoActionBar the solution is as follows:

Kotlin version
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    setupToolbar()
    
}

private fun setupToolbar() {
    setHasOptionsMenu(true)
    // The other option is using val toolbar = findViewById(R.id.toolvar) 
    // and add as parameter instead of the binding option
    (activity as AppCompatActivity).setSupportActionBar(binding.toolbar) 
    (activity as AppCompatActivity).supportActionBar?.setDisplayShowTitleEnabled(false)
}

override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
    super.onCreateOptionsMenu(menu, inflater)
    inflater.inflate(R.menu.my_menu, menu)
}


override fun onOptionsItemSelected(item: MenuItem): Boolean {
    return when (item.itemId) {
        R.id.menu_item_1
            //TODO: implement something here for option 1
            true
        }
        R.id.menu_item_2 -> {
            //TODO: implement something here for option 2
            true
        }
        else -> super.onOptionsItemSelected(item)
    }
}

Solution 10 - Android

Set setHasOptionsMenu(true) in onCreateView() method in fragment.

@Override

 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
 {
    Viewroot=inflater.inflate(R.layout.fragment_client_requestfragment,container,false);
  hideKeyboard();
    getemail = getArguments().getString("email_id");
    Log.e("email_id from activity",getemail);
    setHasOptionsMenu(true);
    return root;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAndroid_programmer_officeView Question on Stackoverflow
Solution 1 - AndroiddangVarmitView Answer on Stackoverflow
Solution 2 - AndroidanimalizeView Answer on Stackoverflow
Solution 3 - AndroidAnisetti NagendraView Answer on Stackoverflow
Solution 4 - AndroidHaris RibicView Answer on Stackoverflow
Solution 5 - AndroidKen Ratanachai S.View Answer on Stackoverflow
Solution 6 - AndroidMorenoView Answer on Stackoverflow
Solution 7 - AndroidnGLView Answer on Stackoverflow
Solution 8 - AndroidMichael MarsellaView Answer on Stackoverflow
Solution 9 - AndroidJorge CasariegoView Answer on Stackoverflow
Solution 10 - AndroidNimisha PatelView Answer on Stackoverflow