My Fragment class:
Toolbar toolbar;
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
toolbar = getView().findViewById(R.id.toolbar3);
toolbar.inflateMenu(R.menu.menufragmentmain);
setHasOptionsMenu(true); //i also tried putting this function in oncreate function
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
Toast.makeText(getActivity(), "i never enter this function also" , Toast.LENGTH_LONG).show();
super.onCreateOptionsMenu(menu,inflater);
inflater.inflate(R.menu.menufragmentmain, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Toast.makeText(getActivity(), "i never enter this function" , Toast.LENGTH_LONG).show();
//some switch cases.....
return super.onOptionsItemSelected(item);
}
I've got a stupid error which I cant find unfourtantly. I've got a simple toolbar for my fragment. In onViewCreated I inflate my actionbar menu with my toolbar.
The issue is that the functions onCreateOptionsMenu and 'onOptionsItemSelected' are never called. I've got no clue why.
Things i checked in other similar questions with the same issue:
I checked if my main activity has a onCreateOptionsMenu or'onOptionsItemSelected'. It doesn*t
Checked if my style class has NOT: android:theme="#android:style/Theme.Black.NoTitleBar
None of the points unfourtantly work. What did I miss. Do I need to check something else?
As per the Fragment-owned app bar guide which explains how to use a Fragment-owned Toolbar, you do not use any of the setHasOptionsMenu(), onCreateOptionsMenu(), or onOptionsItemSelected() APIs - those are only used for activity owned app bars.
Instead, you would follow the guide for handling menu click events by using the Toolbar APIs:
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
toolbar = getView().findViewById(R.id.toolbar3);
toolbar.inflateMenu(R.menu.menufragmentmain);
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
Toast.makeText(getActivity(), "onMenuItemClick called" , Toast.LENGTH_LONG).show();
//some switch cases.....
return true;
}
});
}
Set up the toolbar in the host Activity. Then override the menu handling in each Fragment wherever necessary.
Here's some generic scaffolding (with comments):
public class MyFragment extends Fragment {
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Report that this Fragment has an options menu
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(#NonNull Menu menu, #NonNull MenuInflater inflater) {
// Inflate then menu, and THEN call super()
// Note the order of the invocations
inflater.inflate(R.menu.my_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
// Handle menu item selections
final int itemId = item.getItemId();
switch(itemId) {
case R.id.my_menu_option_x: ...; return true;
case R.id.my_menu_option_y: ...; return true;
case R.id.my_menu_option_z: ...; return true;
default: return super.onOptionsItemSelected(item);
}
}
}
Related
I'm having a ToolBar made as ActionBar in a Fragment. I'm able to add ActionBar menu items but I'm not able to receive click response when I click on any ActionBar menu item.
I have read a lot of similar questions, I tried all but I'm still facing issue, so asked a question here.
The Fragment
public class DetailFragment extends Fragment {
#Override
public View onCreateView(#NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
setHasOptionsMenu(true);
return inflater.inflate(R.layout.project_detail, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mToolBar = (Toolbar)view.findViewById(R.id.tb_toolbar);
((AppCompatActivity)getActivity()).setSupportActionBar(mToolBar);
mToolBar.setTitle(R.string.project_details);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.project_detail_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.options:
// do something
break;
}
return true;
}
In my case in code above, onOptionsItemSelected is not even getting called.
Any pointers why ?
The Activity where I'm inflating this Fragment -
public class TestJust extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test_just);
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.container, new ProjectDetailFragment());
ft.commit();
}
}
project_detail_menu.xml -
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
>
<item
android:id="#+id/options"
android:title="options"
android:icon="#android:drawable/ic_menu_more"
app:showAsAction="always"/>
</menu>
Most probably your problem is that you're always returning true from the activity's onOptionsItemSelected method.
When you return true, you consume the click event inside the method in the activity, that's why the click event never reaches the onOptionsItemSelected method inside your fragment.
Try this
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear()
inflater.inflate(R.menu.project_detail_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.options:
// do something
return true;
default:
return super.onOptionsItemSelected(item);
}
Solution:
You are calling setHasOptionsMenu(true); in onCreateView()
Please call that method in onCreate()
Like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
Calling this method in onCreate() ensures that the menu must participate in Fragment.
Then,
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu_items, menu);
}
Finally,
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.options:
// do something
break;
}
return super.onOptionsItemSelected(item);
It should work now.
initialize option in onCreateOptionMenu then check it. you only inflate menu, use without initialize option, first initialize then use it.
like: MenuItem item = menu.findItem(R.id.option);
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem item = menu.findItem(R.id.option);
}
switch (item.getItemId()) {
case R.id.options:
// do something
return true;//<- Here you need to return true because breaking compile from this line returns default false;
default:
return super.onOptionsItemSelected(item);
}
I have an ActionBarActivity and one Fragment. The Activity has no menu inflated, while the Fragment has a menu with two buttons. Fragment menu is visible, but the buttons don't react at all when tapped. At debugging I can see that both onCreateOptionsMenu() for Fragment and Activity get called, but when tapping buttons no onOptionsItemSelected() gets called, neither from Activity nor from Fragment.
Activity
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return false;
}
Fragment
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mainActivity = (NavigationActivity)getActivity();
setHasOptionsMenu(true);
}
#Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState){
return (ScrollView) inflater.inflate(R.layout.tutoring_detail, container, false);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.query_details_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.accept_query:
respondToQuery(true);
return true;
case R.id.decline_query:
respondToQuery(false);
return true;
default:
break;
}
return false;
}
Menu to be displayed in Fragment
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<item
android:id="#+id/accept_query"
android:orderInCategory="100"
app:showAsAction="always"
android:checkable="true"
style="?android:attr/borderlessButtonStyle"
app:actionViewClass="android.widget.ImageButton"/>
<item
android:id="#+id/decline_query"
android:orderInCategory="101"
app:showAsAction="always"
android:checkable="true"
style="?android:attr/borderlessButtonStyle"
app:actionViewClass="android.widget.ImageButton"/>
</menu>
In the Activity class,
#Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
return false;
}
In the Fragment,
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Toast.makeText(getActivity(), "called " + item.getItemId(), Toast.LENGTH_SHORT).show();
return super.onOptionsItemSelected(item);
}
You must use super.onOptionsItemSelected(item) in the parent activity's onOptionsItemSelected(...) method.
From Activity | Android Developers:
Derived classes should call through to the base class for it to perform the default menu handling.
Try moving setHasOptionsMenu(true) inside of the onCreateView() method in your Fragment instead of onCreate().
I had a similar issue after making special layout for my action button (I made an Image Button and needed to pad it and change some other things so I had to use layout for it).
Then onOptionsItemSelected lost connection with this imageButton so I just use clickListener for it inside onCreateOptionsMenu. It might not be the best practice, maybe there is a better solution, but this is what solve my problem.
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.picker_list_menu, menu);
MenuItem itemDone = menu.findItem(R.id.menu_done);
MenuItemCompat.setActionView(itemDone, R.layout.menu_layout_done);
menuDoneIB = (ImageButton) MenuItemCompat.getActionView(itemDone);
itemDone.getActionView().setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//your code..
}
});
}
Try using oncreateview
public static class ExampleFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, container, false);
}
}
If you have dynamically changed menu item, for instance, a badge menu (https://stackoverflow.com/a/16648170/2914140 or https://stackoverflow.com/a/26017587/2914140), you should initialize the item in onCreateOptionsMenu and re-set setOnClickListeners after every change of the item.
In my case:
private MenuItem menuItem;
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_catalog, menu);
menuItem = menu.findItem(R.id.action_badge);
writeBadge(0);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_badge) {
// Your code.
return true;
}
return super.onOptionsItemSelected(item);
}
private void writeBadge(int count) {
MenuItemCompat.setActionView(menuItem, R.layout.item_badge);
RelativeLayout layout = (RelativeLayout) MenuItemCompat.getActionView(menuItem);
// A TextView with number.
TextView tv = (TextView) layout.findViewById(R.id.badge);
if (count == 0) {
tv.setVisibility(View.INVISIBLE);
} else {
tv.setVisibility(View.VISIBLE);
tv.setText(String.valueOf(count));
}
// An icon, it also must be clicked.
ImageView imageView = (ImageView) layout.findViewById(R.id.image);
View.OnClickListener onClickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
onOptionsItemSelected(menuItem);
}
};
menuItem.getActionView().setOnClickListener(onClickListener);
imageView.setOnClickListener(onClickListener);
}
I am passing the click event to fragment from the activity. This worked for me.
#Override
public boolean onOptionsItemSelected(#NonNull MenuItem item) {
return getSupportFragmentManager().getFragments().get(getSupportFragmentManager().getFragments().size() - 1)
.onOptionsItemSelected(item);
}
I using menu drawer which has more Fragments. In some Fragments I have menu item REFRESH but in some fragments I want hide this menu item (I don't want show menu but I don't want hide ActionBar).
I try add override onCreateOptionsMenu() to Fragment where I don't want show this menu item but I can not get it to work. I try many way see commented line in code. Does any idea where is problem? And last this menu item go to hide when I activate menu drawer when is called onPrepareOptionsMenu() in MainActivity but I need do this when I'm in Fragment.
Fragment where I want hide menu item REFRESH:
public class FindPeopleFragment extends Fragment {
public FindPeopleFragment(){}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_find_people, container, false);
//setHasOptionsMenu(false);
return rootView;
}
private Menu menu=null;
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater)
{
inflater.inflate(R.menu.main, menu);
this.menu=menu;
menu.findItem(R.id.refresh).setVisible(false);
getActivity().invalidateOptionsMenu();
//setHasOptionsMenu(false);
super.onCreateOptionsMenu(menu,inflater);
}
}
MainActivity where is defined MENU DRAWER:
//Slide menu item click listener
private class SlideMenuClickListener implements
ListView.OnItemClickListener {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
// display view for selected nav drawer item
displayView(position);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// toggle nav drawer on selecting action bar app icon/title
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
switch (item.getItemId()) {
case R.id.refresh:
Toast.makeText(this, "Refreshing data...", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
// Called when invalidateOptionsMenu() is triggered
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
menu.findItem(R.id.refresh).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
In the fragment where you want to hide the Item
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem item=menu.findItem(R.id.action_search);
if(item!=null)
item.setVisible(false);
}
and in onCreate() of your fragment
setHasOptionsMenu(true);
In the Fragment where you don't want to show any menu options, you need setHasOptionsMenu(false); in the onCreate(), like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(false);
}
However, the menu that is being shown that you would like to hide (REFRESH), belongs to MainActivity. That is why it is always shown. Since you want to control the menu at the Fragment level (and not show an Activity options menu), my suggestion is to delete the menu code from the Activity and implement it in your Fragment.
Activitys and Fragments can each have their own separate menus. See this link.
please try this
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.clear();
}
and put this on your fragmen's onCreate()
setHasOptionsMenu(true);
In Fragment Class
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
}
in Kotlin for those who needs it
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
menu.clear()
}
I used the code below for hiding menu items in a fragment where I don't want to use it.
Note: Please read comment
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
Fragment whichFragment=getVisibleFragment();//getVisible method return current visible fragment
String shareVisible=whichFragment.getClass().toString();
if(shareVisible.equals(AccFragment.class.toString())
||shareVisible.equals(SocFragment.class.toString())
||shareVisible.equals(DevFragment.class.toString())
){
MenuItem item=menu.findItem(R.id.action_share);
item.setVisible(false);
}
return super.onCreateOptionsMenu(menu);
}
in Kotlin
override fun onPrepareOptionsMenu(menu: Menu) {
val item: MenuItem = menu.findItem(R.id.action_search)
item.isVisible = false
}
in onCreate() of your fragment
setHasOptionsMenu(true)
There are many different versions of similar solutions but unfortunately, none of them worked for me. I am sharing what eventually was useful for me to hide the whole overflow menu with multiple menu items. Thought maybe it's useful for anyone.
I grouped my menus with an id and then referred that id
#Override
public void onPrepareOptionsMenu(Menu menu) {
menu.setGroupVisible(R.id.menu_overflow, false);
super.onPrepareOptionsMenu(menu);
}
If you want to hide any individual menu item then you can use
menu.getItem(R.id.action_licenses).setVisible(false);
Important thing is that you should have setOptionsMenu(true) in onViewCreated()
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
setHasOptionsMenu(true);
Call setHasOptionMenu(true) in onCreateView()
and Do not call super.onCreateOptionsMenu() in fragment's onCreateOptionMenu() instead call menu.clear() because this will override the existing menu with the activity's menu
This worked in my case.
Or solve it in the same Fragment which created the menu, if you host the Actionbar on Activity level. This way you don't have to add it on every other Fragment where you don't want to show it:
public override void OnDestroy()
{
base.OnDestroy();
HasOptionsMenu = false;
}
Add these functions to your Fragment
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public void onPrepareOptionsMenu(Menu menu) {
MenuItem item=menu.findItem(R.id.delete);
item.setVisible(false);
}
Firstly in your Activity that has the toolbar, create a method that sets up the overflow menu for you:
public void setUpOptionMenu(Toolbar toolbar){
this.setSupportActionBar(toolbar);
}
In your fragments onCreateView() method, get the reference of your current activity and call your activities setUpOptionMenu() method:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
...
...
public void ((YourActivityName)this.getActivity()).setUpOptionMenu(null);
...
...
}
Cheers!!!
Overrride the following method just in your fragment and it will do the trick.
#Override
public void onCreateOptionsMenu(Menu menu,MenuInflater inflater) {
// Do something that differs the Activity's menu here
getActivity().getMenuInflater().inflate(R.menu.drawer, menu);
}
2022 KOTLIN
On your activity, where you navigate to fragments, You can try like below, On below code, Tested on Side Navigation view, It has been shown wherever needed using toolbar.inflateMenu(R.menu.toolbar_menu) and hidden using toolbar.menu.clear() on toolbar reference.
binding.naviSideNav.setNavigationItemSelectedListener(NavigationView.OnNavigationItemSelectedListener {
when (it.itemId) {
R.id.side_nav_home->{
toolbar.title=""
toolbar.menu.clear()
toolbar.inflateMenu(R.menu.toolbar_menu)
toolbar.setBackgroundColor(ContextCompat.getColor(this,R.color.home_screen_bg))
navController.navigate(R.id.navigation_home)
}
R.id.side_nav_appointments->{
}
R.id.side_nav_ehr->{
}
R.id.side_nav_invoices->{
}
R.id.side_nav_settings->{
toolbar.title=getString(R.string.nav_menu_Settings)
toolbar.menu.clear()
toolbar.setBackgroundColor(ContextCompat.getColor(this,R.color.home_screen_bg))
navController.navigate(R.id.navigation_settings)
}
R.id.side_nav_logout->{
}
}
binding.dlt.closeDrawer(GravityCompat.START)
true
})
Clean and redraw menu item
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
menu.clear()
inflater.inflate(R.menu.main_menu, menu)
menu.findItem(R.id.id_menu_search)?.isVisible = true
super.onCreateOptionsMenu(menu, inflater)
}
I have checked the answers but now the optionMenu has been deprecated in the latest Android api level
setHasOptionsMenu(false)
so for the people who are using MenuProvider for optionMenu can use the
setMenuVisibility(false)
like this in fragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setMenuVisibility(false)
}
Just find the item you want to hide using findItem then set its visibility to false.
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
MenuItem item = menu.findItem(R.id.action_settings);
item.setVisible(false);
}
I have Action Bar in my application. I am adding action items using menu.xml. I am using action bar-compat as my support library. I observed a weird issue where my action items are getting duplicated.
I am finding this issue randomly when leave my device idle or work with other applications. Please find the screen shot and my code below:
private LoginWebActivity mContext;
private final String TAG = "LoginFragment";
// for metrics
private String mPageNameSignIn = "signin";
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.webview, container, false);
return mView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mContext = (LoginWebActivity) getActivity();
initFragment();
}
#Override
public void onResume() {
super.onResume();
}
/**
* Initialises the views and variables of the fragment.
*/
#SuppressLint({ "JavascriptInterface", "SetJavaScriptEnabled" })
protected void initFragment() {
mWebView = (WebView) mView.findViewById(R.id.webView);
Bundle b = mContext.getIntent().getExtras();
if (b != null) {
mUrl = b.getString(Constants.EXTRA_WEB_LOGIN_URL);
}
super.initFragment();
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.signin, menu);
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Navigate
switch (item.getItemId()) {
case R.id.menu_item_signup:
mContext.onSignUpClick();
break;
case android.R.id.home:
if (!goBack())
getActivity().finish();
default:
break;
}
return super.onOptionsItemSelected(item);
}
My XML :
<?xml version="1.0" encoding="utf-8"?>
<item
android:id="#+id/menu_item_signup"
allergy:showAsAction="ifRoom"
android:title="#string/sign_up">
</item>
You must clear your menu object before adding items. I had the same problem and this was the best solution that I've found.
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.signin, menu);
super.onCreateOptionsMenu(menu, inflater);
}
Pretty late to this party, but for anyone that comes across this via the Google like I did, here's the real problem.
You didn't post your Activity code that's creating the Fragment, but I will venture to guess that it looks something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
Fragment fragment = ...
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
The problem with this is that when the activity goes through its lifecycle (which would happen "when leave my device idle or work with other applications", as you say), the system will save and restore the state of fragments for you. But with this code, you also are adding a new fragment to your Activity, so you end up with multiple fragments running in your activity, each adding an item to the menu.
While the posted workaround will address the duplicate menu entries issue, it would leave these extra fragment instances lying around, which is obviously not what you want.
The correct fix is a simple null check:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
if (savedInstanceState == null) {
Fragment fragment = ...
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragment_container, fragment)
.commit();
}
}
Since the system will indicate the activity is being recreated with a non-null Bundle for the savedInstanceState parameter, you check this to determine whether you should be creating and adding a new fragment.
Hope that helps.
i used Renan Bandeira's great solution and i had some error so i changed it a little bit and worked for me too . then I'm sharing my experience : maybe it become helpful again all credit goes to him for great solution .
#Override
public void onCreateOptionsMenu(Menu menu ) {
menu.clear();
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu."your current activity name ", menu);
return true;
}
I facing the same problem and exactly as state by #Szymon "I add menu option from the fragment, I create multiple fragments?" So my solution was look like below.
onCreate :
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.menu, menu);
menu.findItem(R.id.action_one).setVisible(true);
menu.findItem(R.id.action_two).setVisible(false);
super.onCreateOptionsMenu(menu, inflater);
}
onPrepare :
#Override
public void onPrepareOptionsMenu(Menu menu) {
if (isAdded()
&& !isDetached()
&& isVisible()
&& !isRemoving()
)
{
// show the menu
if (menu.findItem(R.id.action_one).isVisible())
menu.findItem(R.id.action_one).setVisible(true);
// hide the menu
if (menu.findItem(R.id.action_two).isVisible())
menu.findItem(R.id.action_two).setVisible(false);
}
}
You should use the following method instead and you will not see the duplicates anymore (notice that it has only a Menu object as argument)
#Override
public boolean onCreateOptionsMenu( Menu menu )
{
getMenuInflater().inflate( R.menu.main_activity_menu, menu );
return true;
}
I have placed setHasOptionsMenu(true) inside onCreateView, but I still can't call onCreateOptionsMenu inside fragments.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
setHasOptionsMenu(true);
return inflater.inflate(R.layout.facesheet, container, false);
}
Below is my onCreateOptionsMenu code.
#Override
public boolean onCreateOptionsMenu(com.actionbarsherlock.view.Menu menu) {
getSupportMenuInflater().inflate(R.menu.layout, menu);
return (super.onCreateOptionsMenu(menu));
}
The error message I get:
The method onCreateOptionsMenu(Menu) of type Fragment must override or implement a supertype method.
try this,
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_sample, menu);
super.onCreateOptionsMenu(menu,inflater);
}
Finally, in onCreateView method, add this line to make the options appear in your Toolbar
setHasOptionsMenu(true);
Your already have the autogenerated file res/menu/menu.xml defining action_settings.
In your MainActivity.java have the following methods:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_settings:
// do stuff, like showing settings fragment
return true;
}
return super.onOptionsItemSelected(item); // important line
}
In the onCreateView() method of your Fragment call:
setHasOptionsMenu(true);
and also add these 2 methods:
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.fragment_menu, menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_1:
// do stuff
return true;
case R.id.action_2:
// do more stuff
return true;
}
return false;
}
Finally, add the new file res/menu/fragment_menu.xml defining action_1 and action_2.
This way when your app displays the Fragment, its menu will contain 3 entries:
action_1 from res/menu/fragment_menu.xml
action_2 from res/menu/fragment_menu.xml
action_settings from res/menu/menu.xml
I tried the #Alexander Farber and #Sino Raj answers. Both answers are nice, but I couldn't use the onCreateOptionsMenu inside my fragment, until I discover what was missing:
Add setSupportActionBar(toolbar) in my Activity, like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.id.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
}
I hope this answer can be helpful for someone with the same problem.
Call
setSupportActionBar(toolbar)
inside
onViewCreated(...)
of Fragment
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
((MainActivity)getActivity()).setSupportActionBar(toolbar);
setHasOptionsMenu(true);
}
Set setHasMenuOptions(true) works if application has a theme with Actionbar such as Theme.MaterialComponents.DayNight.DarkActionBar or Activity has it's own Toolbar, otherwise onCreateOptionsMenu in fragment does not get called.
If you want to use standalone Toolbar you either need to get activity and set your Toolbar as support action bar with
(requireActivity() as? MainActivity)?.setSupportActionBar(toolbar)
which lets your fragment onCreateOptionsMenu to be called.
Other alternative is, you can inflate your Toolbar's own menu with toolbar.inflateMenu(R.menu.YOUR_MENU) and item listener with
toolbar.setOnMenuItemClickListener {
// do something
true
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_add_customer, container, false);
setHasOptionsMenu(true);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_sample, menu);
super.onCreateOptionsMenu(menu,inflater);
}
You can do easily as,
inside your fragment on Create method,
setHasOptionsMenu(true)
and now you can override,
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
menu.clear()
}