How can I refresh the ActionBar when onPrepareOptionsMenu switched menu entries?
Solution 1
My method of choice is to create a helper class. For example:
class VersionHelper
{
static void refreshActionBarMenu(Activity activity)
{
activity.invalidateOptionsMenu();
}
}
Now in your code above, replace invalidateOptionsMenu();
with:
if (Build.VERSION.SDK_INT >= 11)
{
VersionHelper.refreshActionBarMenu(this);
}
Credit for this method goes to CommonsWare (search for HoneycombHelper, and check out his books - highly recommended)
Solution 2
Thanks to the accepted answer. I am using ActionBarActivity. in this class you can use
supportInvalidateOptionsMenu();
Solution 3
Use
ActivityCompat.invalidateOptionsMenu(Activity activity)
from the compatibility library.
See: https://stackoverflow.com/a/14748687/435855
Solution 4
save a reference to the menu and call:
this.menu.clear();
this.onCreateOptionsMenu(this.menu);
Solution 5
Based on "Klaasvaak" answer above. I am using its subMenus. This works for me :
// Declare and save the menu as global, so it can be called anywhere.
Menu absTopSubMenus;
public boolean onCreateOptionsMenu(Menu menu) {
absTopSubMenus = menu; // Used for re-drawing this menu anywhere in the codes.
// The remainder of your code below
}
Then, to re-draw this, just call :
// Redraw the top sub-menu
absTopSubMenus.clear();
onCreateOptionsMenu(absTopSubMenus);
Harald Wilhelm
Updated on December 14, 2020Comments
-
Harald Wilhelm over 3 years
Within my apps I often enable/disable menu entries and do make them visible from onPrepareOptionsMenu.
Today I started to add the android:showAsAction menu attribute to some of my Android 2.x apps to show menu entries used most on the ActionBar.
The ActionBar does not reflect the enable/disable and visibility immediately. I need to click on the menu dropdown on the right to see this change happen.
Ok, I do understand that the menu fires onPrepareOptionsMenu. But what do I need to do to refresh the ActionBar? I think this change needs to be applied from within onOptionsItemSelected but I don't know what I should call.
Here's the menu:
<item android:icon="@drawable/ic_menu_mapmode" android:id="@+id/men_mapview" android:showAsAction="ifRoom|withText" android:title="@string/txt_mapview" /> <item android:icon="@drawable/ic_menu_mapmode" android:id="@+id/men_satelliteview" android:showAsAction="ifRoom|withText" android:title="@string/txt_satelliteview" />
Here's the onPrepareOptionsMenu:
@Override public boolean onPrepareOptionsMenu(final Menu menu) { MenuItem menuItemMapView = menu.findItem(R.id.men_mapview); MenuItem menuItemSatelliteView = menu.findItem(R.id.men_satelliteview); if (mapView.isSatellite()) { menuItemMapView.setEnabled(true).setVisible(true); menuItemmenuItemSatelliteView.setEnabled(false).setVisible(false); } else { menuItemMapView.setEnabled(false).setVisible(false); menuItemmenuItemSatelliteView.setEnabled(true).setVisible(true); } return super.onPrepareOptionsMenu(menu); }
Here's the onOptionsItemSelected
@Override public boolean onOptionsItemSelected(final MenuItem menuItem) { switch (menuItem.getItemId()) { case R.id.men_mapview: mapView.setSatellite(false); mapView.setStreetView(true); mapView.invalidate(); invalidateOptionsMenu(); // This works on Android 3.x devices only return true; case R.id.men_satelliteview: mapView.setSatellite(true); mapView.setStreetView(false); mapView.invalidate(); invalidateOptionsMenu(); // This works on Android 3.x devices only return true; } return super.onOptionsItemSelected(menuItem); }
EDIT: If I add invalidateOptionsMenu this works on Android 3.x apps but crashes on Android 2.x devices because of a missing method. What's the recommended way to do it right?
-
topwik over 11 yearswhat's the differnece between your answer and simply putting the version check around his initial call of if (Build.VERSION.SDK_INT >= 11) { invalidateOptionsMenu(); }? you could possibly stick the version check in the versionHelper method call?
-
Tony Chan over 11 years@towpse The reason he has the helper class structured as it is is to avoid a crash due to non-backward compatibility. The method
invalidateOptionsMenu()
only exists in API 11 (honeycomb) and up. So if your app is to run on anything lower than API 11 it will crash. To avoid this you wrap the method in question in another static method (e.g.refreshActionBarMenu()
) and only call this static method if you're running on API>11 (thus the version check before you call the static method). This works because theVersionHelper
class isn't loaded until you actually use it. -
topwik over 11 years@Turbo ok cool, thanks for the explanation , so what would one do in the else case? not update the menu at all or what's the older way of doing the menu item update if user is running an older OS?
-
Tony Chan over 11 years@towpse I'm actually figuring out that situation right now. I believe that in the
else
case for this type of situation you should just do nothing. This is because the older way (pre API11) of doing the menu update is in the methodonPrepareOptionsMenu
which automatically gets called every time the user opens the menu. So to handle the older OS and the newer API>11 ones, you put the code for the menu change inonPrepareOptionsMenu
(this is to handle old OS), then to handle newer OS you callinvalidateOptionsMenu
when an event occurs that would trigger a menu change. -
Mike Repass over 10 yearsThis is the correct answer for how to programmatically toggle visibility of Options Menu Items in the Action Bar on pre-API 11 devices.
-
Brill Pappin over 10 yearsI the helper class protects from old SDKs, then why not do the version check inside them method?
-
Ricardo over 10 years@BrillPappin I think that was the point of CommonsWare's book. You don't need the helper if you are having the API check with the rest of your code. Unlike what @Turbo said, the app won't crash in older devices if it doesn't go inside the
if
. By using theVersionHelper
and putting those ifs inside of it, you make your code cleaner. -
lemuel about 10 yearsOn Gingerbread, onCreateOptionsMenu() does not get called after calling this method.
-
Urizev about 10 yearsYes. That's because preHoneycomb does not support on screen buttons and a hardware menu button is expected. So onCreateOptionMenu() method is called when user press menu button. invalidateOptionsMenu is focused on refreshing the actionbar 3.0+ supporting the old menu hardware button.
-
Cjames about 10 yearsGive this man a cookie.... The reason why I can't set the visibility of the menu to false is that I've only use invalidateOptionsMenu(); until I found your answer. Thanks dude.
-
Guy almost 10 yearsThis should be the selected answer.
-
milosmns about 9 yearsSince actions (icons) in Toolbar are now internally represented by a TextView instead of ImageView (and I understand why), I had to manually recolor compound drawables inside the TextView, and additionally assign a TouchListener which would recolor them when pressed/activated. So basically I am coloring icons only. Anyone with a similar situation? Invalidating the menu didn't work for me..
-
Amir Dora. about 6 yearsthis method is deprecated.
-
hetsgandhi almost 5 yearsThank you it saved much of my time!