Reputation: 3245
I have a simple application with options menu, which changing at the start of fragments. The problem is that at the start any fragments except first onCreateOptionsMenu() called twice - within onCreate() and after onResume(). In onCreate() I call it manualy via setHasOptionsMenu(true), but after onResume() it should not happen. Besides, this only occurs after the first fragment started.
Here is base fragments code:
class BaseFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle clicks
return true;
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Create a menu
super.onCreateOptionsMenu(menu, inflater);
}
}
And the changing fragments code in Activity:
public void startFragment(BaseFragment fragment) {
getSupportFragmentManager()
.beginTransaction()
.replace(android.R.id.content, fragment)
.commit();
}
The sample does not use any external library like ActionBarSherlock, only SupportLibrary. I suppose, the problem is in FragmentTransaction replace() method, because it works fine when first fragment is starting. But I don't know, where start to solve the problem. I need exactly replace fragment in View.
Upvotes: 14
Views: 10035
Reputation: 5493
Using the menu?.clear()
is a workaround. Before using that, please make sure you are not recreating the fragment from the MainActivity
. On app recreation due to a configuration change, the app being on the background for a long period of time, etc the activities and fragments are recreated automatically. So, from the MainActivity
we don't nee to create the MyFragment
again.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState == null) { // This is what prevents recreating the fragment
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, MyFragment())
.commit()
}
}
If you don't check that, the fragment will be added again on activity recreation. Therefore, the toolbar will have duplicated menu option items.
Upvotes: 0
Reputation: 10651
The easiest way to solve the issue is to clear the menu just before it's inflated.
menu.clear() will clear any existing menu, and start of with a fresh one.
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
inflater.inflate(R.menu.sample_menu, menu);
}
Upvotes: 8
Reputation: 8680
I know I am late to the party, but ran into the same issue- and my solution was actually to explicitly add
setHasOptionsMenu(false);
to my SupportFragments onCreate function. This prevents any extra calls to activities' onCreateOptionsMenu and to onPrepareOptionsMenu. Hope this helps.
Upvotes: 7
Reputation: 575
You could perhaps try it like this:
private final int MENU_SEARCH=Menu.FIRST;
:
@Override public void onPrepareOptionsMenu(Menu menu) {
if (menu.findItem(MENU_SEARCH)==null) {
menu.add(0, MENU_SEARCH, Menu.NONE, getText(R.string.menu_search));
:
I.e. check if one of your menu items exists in the menu, and if not, probably all of them need to be added.
Upvotes: 0
Reputation: 20569
I guess newly added fragment causes the activities onCreateOptionsMenu to be called again!
1>Try Adding
setRetainInstance(true);
to fragment constructor!
public BaseFragment()
{
setRetainInstance(true);
setHasOptionsMenu(true);
}
This will save/restore the individual states of each of the fragments upon rotation
The problem seems to be related to the fact that Android does not destroy the fragment when the activity is destroyed (when the device is rotated).
I found this here Jake Wharton in SO
Update: 2>Another way is to avoid adding the fragments on the layout file, and also instantiating them manually by calling the constructor/newInstance method.
If you add a fragment on the layout, the android framework will instantiate it for you. Instead of instantiating the fragments manually, you should retrieve it's instance by calling FragmentManager.getFragmentById and use that instance instead.
So always include an ID and/or a tag for your fragments
3>Try with this by calling menu.clear()
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
inflater.inflate(R.menu.call_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
Upvotes: 3