How to add submenu items to ActionBar action in code?

AndroidAndroid 3.0-HoneycombMenuitemAndroid Actionbar

Android Problem Overview


Via xml I can add submenu items to my action in the ActionBar.

enter image description here

main_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_new_form"
          android:icon="@drawable/ic_new_form"
          android:title="@string/menu_new_form"
          android:showAsAction="ifRoom|withText">
        <menu>
            <item android:id="@+id/form1"
                  android:icon="@drawable/attachment"
                  android:title="Form 1"
                  android:onClick="onSort" />
            <item android:id="@+id/form2"
                  android:icon="@drawable/attachment"
                  android:title="Form 2"
                  android:onClick="onSort" />
        </menu>
    </item>
</menu>

But how can I add these sub items via Java code? It doesn't work as below, the sub items are getting added to the wrong action (and also the drawable isn't shown), the very right button, not my 'New Form' button:

enter image description here

main_menu.xml:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/menu_new_form"
          android:icon="@drawable/ic_new_form"
          android:title="@string/menu_new_form"
          android:showAsAction="ifRoom|withText">
    </item>
</menu>

Java Code:

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_menu, menu);

    Log.d("MainMenu", ",menu title0: " + menu.getItem(0).getTitle()); 
    // returns "New Form"

    menu.addSubMenu(0, Menu.NONE, 1, "Form 1").setIcon(R.drawable.attachment);
    menu.addSubMenu(0, Menu.NONE, 2, "Form 2").setIcon(R.drawable.attachment);
    return true;
}

Is there a way to achieve this, adding sub menu items via Java Code instead of XML, without using a PopupMenu (http://developer.android.com/guide/topics/ui/menus.html#PopupMenu)?

Update (Solution):

My final code snippet I ended up with to populate the submenu dynamically, following adamp's reply:

// menu options
private static final int MENU_PREFERENCES = Menu.FIRST;
private static final int MENU_LOGOUT = 2;

@Override
public boolean onCreateOptionsMenu(final Menu menu) {
    super.onCreateOptionsMenu(menu);

    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.main_menu, menu);
    menu.add(0, MENU_PREFERENCES, 0, getString(R.string.general_preferences)).setIcon(
            android.R.drawable.ic_menu_preferences);

    // load all available form templates
    Cursor c = managedQuery(FormsProviderAPI.FormsColumns.CONTENT_URI, null, null, null, null);
    try {
        int ixDisplayName = c.getColumnIndex(FormsProviderAPI.FormsColumns.DISPLAY_NAME);
        int ixId = c.getColumnIndex(FormsProviderAPI.FormsColumns._ID);
        int cnt = 0;
        while (c.moveToNext()) {
            cnt++;
            Log.d("ID: ", "ID: "+ c.getInt(ixId));  // misusing the group id for the form id
            menu.getItem(1).getSubMenu().addSubMenu(c.getInt(ixId), Menu.NONE, cnt, c.getString(ixDisplayName)).setIcon(R.drawable.attachment_dark);
        }
    } catch (Exception e) {
        Log.e(TAG, "Error init form templates list.", e);
    }

    return true;
}

Android Solutions


Solution 1 - Android

Yes, there is.

The addSubMenu method returns a SubMenu object. A SubMenu is also a Menu, so you can call add on it to add items to the submenu rather than the parent menu. Your code above is creating two different submenus for Form 1 and Form 2 rather than two items within a single New Form submenu.

Example:

SubMenu submenu = menu.addSubMenu(0, Menu.NONE, 1, "New Form").setIcon(R.drawable.ic_new_form);
submenu.add("Form 1").setIcon(R.drawable.attachment);

Solution 2 - Android

Adding an ActionProvider maybe it's easier. You can try as explained here

Solution 3 - Android

You should consider to use an ActionProvider

example: https://gist.github.com/sibelius/7ca0b757492ff6740dec

Menu with action provider item

<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <item android:id="@+id/action_companies"
        android:icon="@drawable/ic_list"
        android:title="@string/action_companies"
        app:actionProviderClass="com.example.MyActionProvider"
        app:showAsAction="always"/>
</menu>

Code

public class MyActionProvider extends ActionProvider {

    private Context mContext;

    public MyActionProvider(Context context) {
        super(context);

        mContext = context;
    }

    @Override
    public View onCreateActionView() {
        //LayoutInflater layoutInflater = LayoutInflater.from(mContext);
        return null;
    }

    @Override
    public void onPrepareSubMenu(SubMenu subMenu) {
        super.onPrepareSubMenu(subMenu);

        subMenu.clear();

        subMenu.add("menu 1");
        subMenu.add("menu 2");
        subMenu.add("menu 3");
    }

    @Override
    public boolean hasSubMenu() {
        return true;
    }

    @Override
    public boolean onPerformDefaultAction() {
        return super.onPerformDefaultAction();
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMathias ConradtView Question on Stackoverflow
Solution 1 - AndroidadampView Answer on Stackoverflow
Solution 2 - AndroidFilippo MazzaView Answer on Stackoverflow
Solution 3 - AndroidSibelius SeraphiniView Answer on Stackoverflow