Using a SubMenu in a ListActivity’s Context Menu

One of the limitations of Android’s ListActivity’s Context Menu is that if your context menu gets too large to fit comfortably into one list, shortening it by putting several items into SubMenus requires special handling in onContextItemSelected().

Context menus, by definition, are transient and will be thrown away as soon as they disappear from view. Once you click on a MenuItem that displays a SubMenu, clicking any item in that SubMenu will call the onContextItemSelected(), as expected. What is not expected is that the standard call to get the MenuInfo will return null.

AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)item.getMenuInfo();

In this case, info will be null and trying to use info.position will result in a NullPointerException.

In order to overcome this limitation with submenus, you need to do 3 things:

  1. provide a default section in your switch statement that handles your menu items
  2. save off the info.position to a member variable in your Activity
  3. when you detect that info is null, use the var you created in step 2

The steps outlined above are basic steps, they can be expanded or changed to suit your needs, of course. Please note that the menu items that actually generate the submenu are the ones that execute the default statement.  If your code requires handling of that item, you will need to put the default section code there as well. A simple example of these steps is provided as pseudo-code below:

private int mParentContextMenuListIndex;

@Override
public boolean onContextItemSelected(MenuItem item) {
    AdapterView.AdapterContextMenuInfo info;
    try {
        info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
    } catch (ClassCastException e) {
        Log.e(TAG, "bad menuInfo", e);
        return false;
    }
    //if info == null, it means we have a submenu to deal with, use the saved info.position
    int idxOfList = (info!=null) ? info.position : this.mParentContextMenuListIndex;
    ...
    switch (item.getItemId()) {
        case R.id.context_menu_item_1:
            ... //use idxOfList instead of info.position
            return true;
        case R.id.context_menu_item_2:
            ... //use idxOfList instead of info.position
            return true;
        case R.id.context_menu_item_3:
            ... //use idxOfList instead of info.position
            return true;
        case R.id.context_submenu_item_1:
            ... //use idxOfList instead of info.position
            return true;
        case R.id.context_submenu_item_2:
            ... //use idxOfList instead of info.position
            return true;
        default: //can handle submenus if we save off info.position
            this.mParentContextMenuListIndex = idxOfList;
    }//switch
    return super.onContextItemSelected(item);
}

So there you have it, a quick and easy way to handle submenus inside a list’s context menu.

One thought on “Using a SubMenu in a ListActivity’s Context Menu

Leave a Reply

Your email address will not be published. Required fields are marked *