41

I have a fragment class that extends Fragment and calls setHasOptionsMenu to participate in the menu. This class also implements onCreateOptionsMenu, onPrepareOptionsMenu and onOptionsItemSelected.

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setHasOptionsMenu(true);
        ....
}

I'm dynamically loading this fragment using a FragmentTransaction in my Activity (that extends FragmentActivity).

However none of the menu callbacks (onCreateOptionsMenu, onPrepareOptionsMenu and onOptionsItemSelected) are being called (I've debugged with some breakpoints in those methods) and the menu isn't shown.

Am I missing something? Do I need to add something in my Activity?

I'm using the Android Compatibility Library, compiling with L11 SDK and testing in a Xoom.

EDIT: I've found the problem. My AndroidManifest is targeting L11, this seems to hide the menu button and prevent from the callbacks being called. However if I remove this from the manifest I loose some other features I need (for example the activated state in lists). Does anyone know how to solve this issue (enable the menu button) without removing the targetSdkVersion=11 from the Manifest?

aromero
  • 25,681
  • 6
  • 57
  • 79
  • Can you confirm that your fragment is actually being loaded, i.e. in onCreate being called? – PJL Jun 08 '11 at 14:24
  • Yes I can confirm that. Also I've tried to load it statically, meaning to define the fragment in the activity layout, still no menu. – aromero Jun 08 '11 at 14:36
  • @aromero Nothing obvious springs to mind. You can implement these methods in your fragment class. I'm assuming that onCreateView is returning an inflated view so that your fragment does have a UI? If not then the menu won't be shown. If so then I would suggest debugging the compatibility library sources to see why the messages aren't being dispatched. – PJL Jun 08 '11 at 14:51
  • @PJL thanks will try debugging the library. The fragment does have an UI and everything else is working fine. – aromero Jun 08 '11 at 15:07
  • I've found the problem. I'll edit my question. – aromero Jun 09 '11 at 12:56
  • @aromero I have the following which works a treat for me `` – PJL Jun 09 '11 at 14:39
  • @PJL Are you compiling using SDK 11? Are you testing using a Xoom? In my case only removing the targetSdkVersion=11 makes the difference – aromero Jun 09 '11 at 15:22
  • @aromero OK using 3.0 SDK (10) using the CPL and testing using a Xoom. Maybe the difference is the SDK. – PJL Jun 09 '11 at 15:31
  • @PJL Thanks, BTW API 10 is Android 2.3.3, not 3.0 – aromero Jun 09 '11 at 15:51
  • @aromero sorry yes 11, must of been thinkign about r10 tools. – PJL Jun 09 '11 at 21:41

12 Answers12

29

Aromero, Don't forget to override the onCreateOptionsMenu using the fragment version of the method, similar to this:

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

This goes in the fragment, by the way, and adds to the inflated menu of the Activity, if there is one. Had the same problem myself, until I figured this out.

Kim

user553456
  • 291
  • 2
  • 3
9

If you're having this problem with ActionBarSherlock, you need to make sure your Fragments are SherlockFragments, not mere SupportFragments, and that what you're overriding is

public void onPrepareOptionsMenu (com.actionbarsherlock.view.Menu menu) {

NOT

public void onPrepareOptionsMenu (android.view.Menu menu) {

If you do the latter, you should get some sort of warning about the function being final and you being unable to override it. This is a warning that you're trying to override the wrong function!

If you fix the error by switching the class from SherlockFragment to a mere Fragment, you can create the function . . . but it won't get called.

9

I had the same problem, but i think its better to summarize and introduce the last step to get it working:

  1. Add setHasOptionsMenu(true) method in your Fragment's onCreate(Bundle savedInstanceState) method.

  2. Override onCreateOptionsMenu(Menu menu, MenuInflater inflater) (if you want to do something different in your Fragment's menu) and onOptionsItemSelected(MenuItem item) methods in your Fragment.

  3. Inside your onOptionsItemSelected(MenuItem item) Activity's method, make sure you return false when the menu item action would be implemented in onOptionsItemSelected(MenuItem item) Fragment's method.

An example:

Activity

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

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.activity_menu_item:
        // Do Activity menu item stuff here
        return true;
    case R.id.fragment_menu_item:
        // Not implemented here
        return false;
    default:
        break;
    }

    return false;
}

Fragment

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setHasOptionsMenu(true);
    ....
}

@Override
public void onCreateOptionsMenu(Menu menu) {
    // Do something that differs the Activity's menu here
    super.onCreateOptionsMenu(menu, inflater);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
    case R.id.activity_menu_item:
        // Not implemented here
        return false;
    case R.id.fragment_menu_item:
        // Do Fragment menu item stuff here
        return true;
    default:
        break;
    }

    return false;
}

I hope this will be helpful.

Cheers.

Marco Hernaiz
  • 5,830
  • 3
  • 27
  • 27
6

If you have an activity and a fragment that each loads menu items then you need to take special care of which overrides you use.

Activities can override onOptionsItemSelected and onMenuItemSelected, however fragments can only override onOptionsItemSelected.

If you override onMenuItemSelected in your activity and onOptionsItemSelected in your fragment, your fragment override will never get triggered.

Instead, use onOptionsItemSelected in both activity and fragment.

Error 454
  • 7,255
  • 2
  • 33
  • 48
  • man. thank you. this was the case for me... i don't think I would have ever noticed the 2 different hooks... – tobi.b Mar 22 '13 at 09:47
5

You need to make sure you call setHasOptionsMenu(true); onCreate or onCreateView is called in your fragment.

You also need to implement the override of onCreateOptionsMenu inside your fragment.

Nelson Ramirez
  • 7,864
  • 7
  • 28
  • 34
4

Another possible case is when you use a common id for a common action in each fragment; for instance R.id.action_add

Today I had such situation: hitting the option menu [add] was invoked the "wrong" onOptionItemSelected because each fragment (replaced dynamically using a DrawerLayout) had the same R.id.action_add.

Short story, if you have such situation always check that your fragment is visible:

if (!isVisible()) return false;

Long story, pay attention at the onOptionItemSelected chain!

  MainActivity
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment1
       |
       |  onOptionItemSelected
       +-----------------------
       |     return false
       |
 MyCoolFragment2
       |
       |  onOptionItemSelected
       +-----------------------
       |     return true
       |
[item selection handled]

If you add your fragments with (something like) this:

getSupportFragmentManager()
   .beginTransaction()
   .replace(R.id.content_frame, MyCoolFragment1.newInstance())
   .commit() 

and you have defined the same id for a common action (let's say R.id.action_add) in each fragment; don't forget to add this line to each: if (!isVisible()) return false;

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (!isVisible()) return false; // <-- Not visible? skip!

    if (item.getItemId() == R.id.action_add) {
        //.TODO whatever
        return true;  //.Handled!
    }

    return false; //.Skip
}
Luca Sepe
  • 2,435
  • 1
  • 20
  • 26
  • dude thanx. was returning true in onOptionItemSelected in the activity , it was not reaching the fragments onOptionItemSelected. – shekhar g h Nov 17 '17 at 20:57
3

I had this problem when I was using the ViewPagerIndicator in conjunction with ActionBarSherlock. Although it appeared this was fixed I still ran into the problem. The work around I found was to call into the fragment manually.

@Override
public boolean onOptionsItemSelected(MenuItem item)
{
    Toast.makeText(this, "From activity", Toast.LENGTH_SHORT).show(); // TODO
    Fragment currentFragment = mAdapter.getItem(mPager.getCurrentItem());
    if (currentFragment != null && currentFragment instanceof SherlockFragment)
    {
        ((SherlockFragment)currentFragment).onOptionsItemSelected(item);
    }
    return super.onOptionsItemSelected(item);

}
AlexUT
  • 155
  • 2
  • 5
  • i have the same problem in sherlock fragments. where you put this function? in activity or in fragment? – Paschalis Jul 30 '12 at 03:17
  • 5
    I originally had this code inside the activity, calling the fragment, but this actually isn't necessary. In the fragment's onCreateView or onCreate method just call setHasOptionsMenu(true); Then when you override onOptionsItemSelected and onCreateOptionsMenu they get called correctly. – AlexUT Aug 09 '12 at 01:22
2

I've found the problem. The AndroidManifest is targeting SDK 11, this seems to hide the menu button and prevent from the callbacks being called. I assume that this breaks the compatibility of the menu button that seems to be replaced by the action bar in Android 3.0

aromero
  • 25,681
  • 6
  • 57
  • 79
1

I had same problem and solution that worked for me is:

  1. Remove or comment any onOptionsItemSelected() ,onMenuItemSelected() even onPrepareOptionMenu() and leave in Activity onCreateOptionsMenu() only:

    @Override
    public boolean onCreateOptionsMenu(Menu menu){
    MenuInflater inflater=getMenuInflater();
    inflater.inflate(R.layout.menu, menu);
    return true;
    }
    
  2. In Fragment class, in onCreateView(), put:

    setHasOptionsMenu(true);
    
  3. In Fragment class add :

    @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
     super.onCreateOptionsMenu(menu,inflater);      
     }
    
    @Override
     public boolean onOptionsItemSelected(MenuItem item){           
             switch(item.getItemId()){
             case R.id.action_insert:
                //doing stuff
             return true;
             }
             return false;
         }
    

Tested and worked on Android 4.4

Asad Mahmood
  • 532
  • 1
  • 5
  • 15
Augusto Picciani
  • 788
  • 2
  • 11
  • 31
1

From the android developer site - link

Note: If you inflate menu items from a fragment, via the Fragment class's onCreateOptionsMenu() callback, the system calls onOptionsItemSelected() for that fragment when the user selects one of those items. However, the activity gets a chance to handle the event first, so the system first calls onOptionsItemSelected() on the activity, before calling the same callback for the fragment. To ensure that any fragments in the activity also have a chance to handle the callback, always pass the call to the superclass as the default behavior instead of returning false when you do not handle the item.

Therefore Marco HC is the best answer of all.

Community
  • 1
  • 1
ik024
  • 3,566
  • 7
  • 38
  • 61
1

If your toolbar is defined in the parent activity xml, make sure you do this in your fragment

@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    ....
    Toolbar toolbar = (Toolbar)getActivity().findViewById(R.id.toolbar);
    ((AppCompatActivity)getActivity()).setSupportActionBar(toolbar);
    setHasOptionsMenu(true);
}

And then of course, override onCreateOptionsMenu like below

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

This is the only solution that worked for me!

reavcn
  • 300
  • 2
  • 14
1

I think you have implemented onCreateOptionsMenu, onPrepareOptionsMenu and onOptionsItemSelected in the class that extends Fragment. Try by doing that in your Activity class where you are loading this fragment

Labeeb Panampullan
  • 34,521
  • 28
  • 94
  • 112
  • Yes those methods are implemented in the Fragment class. The Activity is a "multi pane" activity, meaning that the menu should only be shown when that specific fragment is showed. This example implements onCreateOptionsMenu in the Fragment class http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentMenu.html – aromero Jun 08 '11 at 14:07
  • You can quite happily put the menu methods in the class that extends Fragment. – PJL Jun 10 '11 at 09:17
  • Yes PJL, You are right we can put this methods there. But once i tried in fragment class it didn't worked for me and when i changed to Main activity it worked. May be i have done something wrong. – Labeeb Panampullan Jun 10 '11 at 09:40