96

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.

Programmer Bruce
  • 64,977
  • 7
  • 99
  • 97
brockoli
  • 4,516
  • 7
  • 38
  • 45

6 Answers6

179

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.

Nightfirecat
  • 11,432
  • 6
  • 35
  • 51
CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 2
    Tried Option #1 and this did the trick. Since I was trying to update the UI in a callback from a separate thread, it was throwing an exception since I wasn't actually on the UI thread. To fix this, I created a Handler and sent a refresh message to the handler when my callback was called. But ultimately I used getActivity().invalidateOptionsMenu() to refresh the menu. – brockoli Apr 24 '11 at 14:06
  • @brockoli: Ah, good! Given the phrasing of the Javadocs for that method, I was skeptical that it would have the desired effect, though it would seem like it was the reason they added it to API Level 11 in the first place. Glad to hear it's working for you! – CommonsWare Apr 24 '11 at 14:10
  • I've been hitting my head against the wall trying to figure this out and it works like a charm! – MinceMan Sep 29 '12 at 14:19
  • Option 1 didn't work for me. onPrepare/onCreate wasn't invoked after the invalidate. I chose to hang on to the Menu object and change it dynamically. – AlikElzin-kilaka Dec 17 '12 at 09:20
  • Call from fragment refresh items, but click listener is not called after that. – Vasil Valchev Aug 02 '13 at 21:12
  • 7
    If you're using the support library, use `supportInvalidateOptionsMenu()` instead – Tim Kist Oct 13 '15 at 12:28
  • Thanks :) ! Really helped me out. –  Nov 21 '16 at 11:19
  • 2
    @TimKist, `supportInvalidateOptionsMenu()` is now deprecated; you can safely use `invalidateOptionsMenu()`. – c0dehunter Jun 07 '18 at 10:09
14

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;
}
JJD
  • 50,076
  • 60
  • 203
  • 339
cV2
  • 5,229
  • 3
  • 43
  • 53
  • How did you get a handle to the ActionBar view with `mnuTopMenuActionBar_`? – Unpossible Jan 02 '12 at 23:33
  • 1
    when the action bar gets initialized, i saved the view to a member variable... like this: @Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater inflater = getMenuInflater(); inflater.inflate(R.menu.magazine_swipe_activity, menu); mnuTopMenuActionBar_ = menu; return true; } – cV2 Jan 04 '12 at 09:06
  • By doing that, you can have synchronization issues right? I mean. you dont know EXACTLY when onCreateOptionMenu is going to run, so you may reach your piece of code with the `mnuTopMenuActionBar_` uninitialized, right? How would you work around that? – acrespo Oct 15 '13 at 20:42
  • hey, if actionbar is used (yes, here it is) this method is always called, so there's no problem with that... (directly at activity start) http://stackoverflow.com/questions/7705927/android-when-is-oncreateoptionsmenu-called-during-activity-lifecycle – cV2 Oct 15 '13 at 22:05
13

To refresh menu from Fragment simply call:

getActivity().invalidateOptionsMenu();
CoolMind
  • 26,736
  • 15
  • 188
  • 224
4

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

JJD
  • 50,076
  • 60
  • 203
  • 339
ASK
  • 117
  • 1
  • 12
2

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();
    }
}
Maxdestroyer
  • 185
  • 4
  • 12
saranya
  • 228
  • 2
  • 11
1

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.

Jay Snayder
  • 4,298
  • 4
  • 27
  • 53