96
votes

I have an Activity that has 2 fragments. Both are ListFragments and both contribute MenuItems to the Menu. I have one MenuItem that I've set the attribute android:showAsAction to have it show as a button on the ActionBar. Which works fine.

Now the MenuItem is state dependent. It's a Pause/Resume menu option for pausing and resuming a queue. My problem is I can't figure out how to set it's initial statue when the Fragment is created.

It's state is dependent on the whether the queue is paused or not. So I have an AsyncTask that gets the queue and sets a boolean (paused) based on the state of the queue. I'm calling onPrepareOptionsMenu to set the text for the Pause menu item based on the last known state of the queue and this works great if I leave the MenuItem in the actual menu. You tap the menu icon and onPrepareOptionsMenu is fired and the menu is updated before it's displayed.

The problem is, if I put that same MenuItem on the ActionBar (showAsAction), how can I force it to update without having to call onPrepareOptionsMenu? I need to be able to do this because on first launch of the app, I send a request to get the queue, but the task returns after the ActionBar is setup and displayed. I've created a handler in my fragment that gets called every time I get a queue update, but from there, how can I update the text for my MenuItem on the ActionBar? I can't seem to find a way to get the currently set Menu to manipulate it except for in onPrepareOptionMenu.

Rob W.

7

7 Answers

176
votes

Option #1: Try invalidateOptionsMenu(). I don't know if this will force an immediate redraw of the action bar or not.

Option #2: See if getActionView() returns anything for the affected MenuItem. It is possible that showAsAction simply automatically creates action views for you. If so, you can presumably enable/disable that View.

I can't seem to find a way to get the currently set Menu to manipulate it except for in onPrepareOptionMenu.

You can hang onto the Menu object you were handed in onCreateOptionsMenu(). Quoting the docs:

You can safely hold on to menu (and any items created from it), making modifications to it as desired, until the next time onCreateOptionsMenu() is called.

14
votes

in my case: invalidateOptionsMenu just re-setted the text to the original one, but directly accessing the menu item and re-writing the desire text worked without problems:

if (mnuTopMenuActionBar_ != null) {
    MenuItem mnuPageIndex = mnuTopMenuActionBar_
        .findItem(R.id.menu_magazin_pageOfPage_text);

    if (mnuPageIndex != null) {
        if (getScreenOrientation() == 1) {
            mnuPageIndex.setTitle((i + 1) + " von " + pages);
        }
        else {
            mnuPageIndex.setTitle(
                (i + 1) + " + " + (i + 2) + " " + " von " + pages);
        }
        // invalidateOptionsMenu();
    }
}

due to the comment below, I was able to access the menu item via the following code:

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

To refresh menu from Fragment simply call:

getActivity().invalidateOptionsMenu();
4
votes

I have used this code:

public boolean onPrepareOptionsMenu (Menu menu) {       
    MenuInflater inflater = getMenuInflater();
    TextView title  = (TextView) findViewById(R.id.title);
    menu.getItem(0).setTitle(
        getString(R.string.payFor) + " " + title.getText().toString());
    menu.getItem(1).setTitle(getString(R.string.payFor) + "...");
    return true;        
}

And worked like a charm to me you can find OnPrepareOptionsMenu here

2
votes

First please follow the two lines of codes to update the action bar items before that you should set a condition in oncreateOptionMenu(). For example:

Boolean mISQuizItemSelected = false;

/**
 * Called to inflate the action bar menus
 *
 * @param menu
 *      the menu
 *
 * @return true, if successful
 */

@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // Inflate the menu items for use in the action bar

    inflater.inflate(R.menu.menu_demo, menu);

    //condition to hide the menus
    if (mISQuizItemSelected) {
        for (int i = 0; i < menu.size(); i++) {
            menu.getItem(i).setVisible(false);
        }
    }

    return super.onCreateOptionsMenu(menu);
}

/**
 * Called when the item on the action bar being selected.
 *
 * @param item
 *      menuitem being selected
 *
 * @return true if the menuitem id being selected is matched
 * false if none of the menuitems id are matched
 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    if (item.getId() == R.id.action_quiz) {
        //to navigate based on the usertype either learner or leo
        mISQuizItemSelected = true;

        ActionBar actionBar = getActionBar();
        invalidateOptionMenu();
    }
}
1
votes

For clarity, I thought that a direct example of grabbing onto a resource can be shown from the following that I think contributes to the response for this question with a quick direct example.

private MenuItem menuItem_;

@Override
public boolean onCreateOptionsMenu(Menu menuF) 
{
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.menu_layout, menuF);
    menuItem_ = menuF.findItem(R.id.menu_item_identifier);
    return true;
}

In this case you hold onto a MenuItem reference at the beginning and then change the state of it (for icon state changes for example) at a later given point in time.

-1
votes

In Kotlin 1.2 simply call:

invalidateOptionsMenu()

and the onCreateOptionsMenu function will be called again.