The MenuPopupHelper class in AppCompat has the @hide annotation. If that's a concern, or if you can't use AppCompat for whatever reason, there's another solution using a Spannable in the MenuItem title which contains both the icon and the title text.
The main steps are:
- inflate your 
PopupMenu with a menu xml file 
- if any of the items have an icon, then do this for all of the items:
- if the item doesn't have an icon, create a transparent icon.  This ensures items without icons will be aligned with items with icons
 
- create a 
SpannableStringBuilder containing the icon and title 
- set the menu item's title to the 
SpannableStringBuilder 
- set the menu item's icon to null, "just in case"
 
 
Pros: No reflection. Doesn't use any hidden apis. Can work with the framework PopupMenu.
Cons: More code. If you have a submenu without an icon, it will have unwanted left padding on a small screen.
Details:
First, define a size for the icon in a dimens.xml file:
<dimen name="menu_item_icon_size">24dp</dimen>
Then, some methods to move the icons defined in xml into the titles:
/**
 * Moves icons from the PopupMenu's MenuItems' icon fields into the menu title as a Spannable with the icon and title text.
 */
public static void insertMenuItemIcons(Context context, PopupMenu popupMenu) {
    Menu menu = popupMenu.getMenu();
    if (hasIcon(menu)) {
        for (int i = 0; i < menu.size(); i++) {
            insertMenuItemIcon(context, menu.getItem(i));
        }
    }
}
/**
 * @return true if the menu has at least one MenuItem with an icon.
 */
private static boolean hasIcon(Menu menu) {
    for (int i = 0; i < menu.size(); i++) {
        if (menu.getItem(i).getIcon() != null) return true;
    }
    return false;
}
/**
 * Converts the given MenuItem's title into a Spannable containing both its icon and title.
 */
private static void insertMenuItemIcon(Context context, MenuItem menuItem) {
    Drawable icon = menuItem.getIcon();
    // If there's no icon, we insert a transparent one to keep the title aligned with the items
    // which do have icons.
    if (icon == null) icon = new ColorDrawable(Color.TRANSPARENT);
    int iconSize = context.getResources().getDimensionPixelSize(R.dimen.menu_item_icon_size);
    icon.setBounds(0, 0, iconSize, iconSize);
    ImageSpan imageSpan = new ImageSpan(icon);
    // Add a space placeholder for the icon, before the title.
    SpannableStringBuilder ssb = new SpannableStringBuilder("       " + menuItem.getTitle());
    // Replace the space placeholder with the icon.
    ssb.setSpan(imageSpan, 1, 2, 0);
    menuItem.setTitle(ssb);
    // Set the icon to null just in case, on some weird devices, they've customized Android to display
    // the icon in the menu... we don't want two icons to appear.
    menuItem.setIcon(null);
}
Finally, create your PopupMenu and use the above methods before showing it:
PopupMenu popupMenu = new PopupMenu(view.getContext(), view);
popupMenu.inflate(R.menu.popup_menu);
insertMenuItemIcons(textView.getContext(), popupMenu);
popupMenu.show();
Screenshot:
