OnOptionsItemSelected in activity is called before onOptionsItemSelected in fragment. Other way possible?

10,696

Solution 1

According to the developers reference,

"Return false to allow normal menu processing to proceed, true to consume it here."

So I would try returning 'false' by default in the Activity's implementation of onOptionsItemSelected(), this way the event will pass on to the Fragment's implementation if it is not caught.

Solution 2

I just encounter this problem, and I have made it work using following code. In the activity's onOptionsItemSelectedfunction, add:

if (id == android.R.id.home){
        Fragment currentFragment = getSupportFragmentManager().findFragmentById(R.id.container);
        if(null != currentFragment && currentFragment.onOptionsItemSelected(item)){
            return true;
        }
    }

And in the fragment's onOptionsItemSelected method, you handle the corresponding things. In this way, if the fragment has any things to do for the menu item, it will do it and return true to stop any other process. And if the fragment does not have anything to do with this item, it will return false or call super.onOptionsItemSelected method which may eventually return false to let others process it.

Solution 3

Not sure if it's possible. In the official docs available here:

http://developer.android.com/guide/topics/ui/actionbar.html#ActionEvents

There is a note, that states the following:

[...] 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.

Solution 4

You can do as @Surely written, it's great idea, but in that case you will call onOptionsItemSelected on fragment without knowing which fragment it is, and you should override onOptionsItemSelected method in all your fragments.

If you only want to call this method for particular fragments, you should find them by tag, which you used when adding them:

case android.R.id.home:
            Fragment frag = getSupportFragmentManager()
                    .findFragmentByTag(FRAGMENT_TAG);

            if(frag != null && frag.isVisible() && frag.onOptionsItemSelected(item)) {
                return true;

Tag is specifying like this:

fragmentManager.beginTransaction()
            .add(containerId, fragment, FRAGMENT_TAG)
Share:
10,696
MrHill
Author by

MrHill

Updated on June 27, 2022

Comments

  • MrHill
    MrHill almost 2 years

    I have an activity which can contain several fragments. Each of the fragments can have their own menu entries in the ActionBar. This works fine so far and each item is clickable and performs the desired action.

    My problem is the following. In the MainActivity I declared the following lines to intercept calls to the HomeIcon of the ActionBar:

    public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
            case android.R.id.home:
                clearBackStack();
                        setHomeFragment();
                return true;
            default:
                return super.onOptionsItemSelected(item);
    
            }
        }
    

    I declared it in the Activity because I wanted that every Fragment should call this so that I don't have to catch the android.R.id.home case in each fragment.

    In one Fragment I am using setDisplayHomeAsUpEnabled(true), so that I get the little arrow left of the ActionBar Icon. When the HomeIcon is clicked in this fragment I don't want to set the HomeFragment, I want to set the Fragment which was last displayed. So I have a onOptionsItemSelected - Method in the Fragment:

    @Override
    public boolean onOptionsItemSelected(MenuItem menuItem) {
    
        switch (menuItem.getItemId()) {
        case android.R.id.home:
            setLastFragment();
                   return true;
        ...
    

    However this does not work the way I wanted it to work. The Activity's onOptionsItemSelected is called first, catches the MenuItem and redirects to the HomeFragment. With the other MenuItems declared in other fragments i can check the see the same behaviour. Activity is called first, doesn't catch the MenuItem (default case) and then redirects to super.onOptionsItemSelected(item).

    So it seems that this is the case how Android handles the Menu Clicks. First Activity, then Fragment. Is there a way to change this? I don't want to put the android.R.id.home-case in every fragment and handle it there. Is there a nicer way to do this?

  • Francesco
    Francesco about 10 years
    This is not what MrHill was asking for! I'm facing the same problem. Normally the activity handles the "Home UP" button. Sometimes we want to do special action when the "Home UP" button is pressed while a certain fragment is currently active. Returning false on the Activity onOptionsItemSelected prevent the activity to handle the case.
  • Tash Pemhiwa
    Tash Pemhiwa almost 8 years
    It is possible, provided you call setHasOptionsMenu(true) during the early part of the Fragment's life cycle, e.g. in onCreateView()