3

我对我的 Android 应用程序进行了一些仪器测试,我想测试我的 Activity 的 onOptionsItemSelected() 方法。

为此,我使用 Instrumentation 的invokeMenuActionSync方法:

这在较新版本的 Android 上运行良好,但似乎不会导致在较旧版本(例如 API10)上调用 onOptionsItemSelected() 方法。

我试过结合其他方法:

if (getInstrumentation().invokeMenuActionSync(activity, R.id.menu_refresh, 0 /* flags */) ||
    getInstrumentation().invokeContextMenuAction(activity, R.id.menu_refresh, 0 /* flags */)) {
   // verify 
}

没有变化。

我正在使用 AppCompat 操作栏。

有没有更好的方法可以始终调用它,或者我可以在旧 API 级别上使用并在两者之间切换?

4

1 回答 1

0

我发现使用检测类调用支持菜单的唯一方法是使用丑陋的反射代码(可能不需要“init”部分中的某些字段和类,抱歉,我也将它们用于其他代码)

// support part
private static Class<?> actionBarActivitySupportClass;  
private static Field mImplField;
private static Class<?> actionBarActivityDelegateBaseClass;
private static Field mActionModeSupportField;
private static Class<?> actionModeSupportImplClass;
private static Field mMenuActionModeSupportField;
private static Class<?> menuBuilderSupportClass;
private static Field mVisibleItemsSupportField;
private static Field mCallbackActionModeSupportField;
private static Class<?> callbackWrapperSupportClass;
private static Field mWrappedSupportField;
private static Method onMenuItemSelectedSupportmethod;
private static Field mActionBarSupportView; 
private static Class<?> actionBarViewSupportClass;
private static Field mOptionMenuSupportField;
private static Method dispatchMenuItemSelected;

static {
    init();
}

private static void init() {
    try {
        actionBarActivitySupportClass = Class.forName("android.support.v7.app.ActionBarActivity"); //$NON-NLS-1$
        mImplField = actionBarActivitySupportClass.getDeclaredField("mImpl"); //$NON-NLS-1$
        mImplField.setAccessible(true);
        actionBarActivityDelegateBaseClass = Class.forName("android.support.v7.app.ActionBarActivityDelegateBase"); //$NON-NLS-1$
        mActionModeSupportField = actionBarActivityDelegateBaseClass.getDeclaredField("mActionMode"); //$NON-NLS-1$
        mActionModeSupportField.setAccessible(true);
        actionModeSupportImplClass = Class.forName("android.support.v7.app.ActionBarImplBase$ActionModeImpl"); //$NON-NLS-1$
        mMenuActionModeSupportField = actionModeSupportImplClass.getDeclaredField("mMenu"); //$NON-NLS-1$
        mMenuActionModeSupportField.setAccessible(true);
        menuBuilderSupportClass = Class.forName("android.support.v7.internal.view.menu.MenuBuilder"); //$NON-NLS-1$
        mVisibleItemsSupportField = menuBuilderSupportClass.getDeclaredField("mVisibleItems"); //$NON-NLS-1$
        mVisibleItemsSupportField.setAccessible(true);
        mCallbackActionModeSupportField = actionModeSupportImplClass.getDeclaredField("mCallback");  //$NON-NLS-1$
        mCallbackActionModeSupportField.setAccessible(true);
        callbackWrapperSupportClass = Class.forName("android.support.v7.app.ActionBarActivityDelegateBase$ActionModeCallbackWrapper"); //$NON-NLS-1$
        mWrappedSupportField = callbackWrapperSupportClass.getDeclaredField("mWrapped"); //$NON-NLS-1$
        mWrappedSupportField.setAccessible(true);
        onMenuItemSelectedSupportmethod = actionModeSupportImplClass.getDeclaredMethod("onMenuItemSelected", new Class[]{menuBuilderSupportClass,MenuItem.class}); //$NON-NLS-1$
        onMenuItemSelectedSupportmethod.setAccessible(true);
        mActionBarSupportView = actionBarActivityDelegateBaseClass.getDeclaredField("mActionBarView"); //$NON-NLS-1$
        mActionBarSupportView.setAccessible(true);
        actionBarViewSupportClass = Class.forName("android.support.v7.internal.widget.ActionBarView");  //$NON-NLS-1$
        mOptionMenuSupportField = actionBarViewSupportClass.getDeclaredField("mOptionsMenu"); //$NON-NLS-1$
        mOptionMenuSupportField.setAccessible(true);
        dispatchMenuItemSelected = menuBuilderSupportClass.getDeclaredMethod("dispatchMenuItemSelected", new Class[]{menuBuilderSupportClass,MenuItem.class}); //$NON-NLS-1$
        dispatchMenuItemSelected.setAccessible(true);
    } catch (ClassNotFoundException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    } catch (SecurityException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    } catch (NoSuchFieldException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    } catch (NoSuchMethodException e) {
        System.out.println("support class not loaded "+e.getMessage()); //$NON-NLS-1$
    }

}

public static void invokeMenu(Instrumentation instrumentation,final Activity activity,final Object item) {
    if ((mImplField != null) && (actionBarActivitySupportClass != null) && (actionBarActivitySupportClass.isInstance(activity)) 
            && (mActionBarSupportView != null) && (mOptionMenuSupportField != null) && (dispatchMenuItemSelected != null)) { 
        activity.runInUiThread(new Runnable() {
            @Override
            public void run() {
                try {
                    Object actionBarActivityDelegateBase = mImplField.get(activity);                
                    if (actionBarActivityDelegateBase != null) {
                        Object actionBarView = mActionBarSupportView.get(actionBarActivityDelegateBase);
                        if (actionBarView != null) {
                            Object mOptionMenu = mOptionMenuSupportField.get(actionBarView);                        
                            dispatchMenuItemSelected.invoke(mOptionMenu, new Object[]{mOptionMenu,item});                       
                        }
                    }                       
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        });
    } else {
        // good old classic way
        instrumentation.invokeMenuActionSync(activity, ((MenuItem)item).getItemId(), 0);
    }

}
于 2015-02-02T13:27:46.873 回答