Print

How to create a shared and extendable menu on Android

Written by Luzian Scherrer on .

Menus are a nice and important human user interface element on Android. They are nice because they add options without adding clutter to the small mobile screen and they are important because they are of great help for users that rely on accessibility.

There is some handy documentation on the Android Developer Website about how to create a menu for one single activity but in the real world the situation is a bit more complex. Larger apps can span dozens of activites and most of the time you want to have different individual menu items on each of those as well as global menu items that are available on all activites. Common examples for global menu items are the "About", "FAQ" or "Support" buttons that you find in apps quite often.

What you certainly do not want to deal with is a copy of the code for the global menu items in each activity. Using inheritance is not an option in many situations neither because you might already have some other class that you are extending.

So how can we solve this problem? Here's our approach:

First we create a class called SharedMenu.java that holds the global menu items ("About" and "FAQ" in our example):

 
public class SharedMenu 
{  
  // start at 1000 ensure that we do not interfere with the activity-specific menu items
  public static final int MENU_ABOUT = 1000;
  public static final int MENU_FAQ   = 1001;
 
  public static void onCreateOptionsMenu(Menu menu, Context ctx) {
    menu.add(Menu.NONE, MENU_FAQ, Menu.NONE,
             ctx.getString(R.string.Faq)).setIcon(R.drawable.ic_menu_faq);
    menu.add(Menu.NONE, MENU_ABOUT, Menu.NONE,
             ctx.getString(R.string.About)).setIcon(R.drawable.ic_menu_about);
  }
 
  public static boolean onOptionsItemSelected(MenuItem item, Activity caller) {
    Intent intent;
    switch (item.getItemId()) {
      case SharedMenu.MENU_ABOUT:
        intent = new Intent(caller, AboutActivity.class);
        caller.startActivity(intent);
        return true;
      case SharedMenu.MENU_FAQ:
        intent = new Intent(caller, FaqActivity.class);
        caller.startActivity(intent);
        return true;
      default:
        return false;
    }
  }
}
 

Then in each activity we add the following two methods to display and handle the menu:

 
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    // add local menu items here or leave blank
    SharedMenu.onCreateOptionsMenu(menu, getApplicationContext());
    return true;
  }
 
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    if(SharedMenu.onOptionsItemSelected(item, this) == false) {
      // handle local menu items here or leave blank
    }
    return super.onOptionsItemSelected(item);
  }
 

This gives us the option to add activity specific menu items if we need them. Here's an example where we add a "Help" button:

 
  private final int MENU_HELP = 1;
 
  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    // this time we add a local menu item:
    menu.add(Menu.NONE, MENU_HELP, Menu.NONE, 
             getString(R.string.Help)).setIcon(R.drawable.ic_menu_help);
    SharedMenu.onCreateOptionsMenu(menu, getApplicationContext());
    return true;
  }
 
  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    if(SharedMenu.onOptionsItemSelected(item, this) == false) {
      // and we handle the local menu items here:
      switch (item.getItemId()) {
        case MENU_ALARM_HELP:
          // insert your  code that handles the menu item
          return true;
      }
    return super.onOptionsItemSelected(item);
  }
 

Please tell us what you think in the comments below and don't forget to let us know in case you have a better solution.