InflateException:无法解析onClick处理程序的菜单项

时间:2012-06-28 13:32:54

标签: android android-actionbar actionbarsherlock

我在6年前问过这个问题。与此同时,Android开发最佳实践已发生变化,我已成为更好的开发人员。

从那时起,我意识到使用onClick XML属性是一种不好的做法,并将其从我工作的任何代码库中删除。

我的所有点击处理程序现在都在应用程序的代码中定义,而不是XML布局!

我从不使用onClick的原因是

  1. 很容易在onClick XML属性的值中出错,这会导致运行时错误
  2. 开发人员可能会重构点击处理程序方法的名称,而不会意识到它是从布局中调用的(参见原因1)
  3. 找出实际调用的方法并不总是显而易见的。特别是如果片段正在使用布局
  4. 将布局与行为的关注分开是好的。使用onClick混合起来,这很糟糕!
  5. 我希望我已经说服你永远不要在布局中使用onClick

    以下是我原来的问题,这是一个非常好的例子,说明为什么使用onClick是一个坏主意。

    ===

    我在XML中定义菜单项,并尝试使用API​​ 11中添加的onClick属性。当在运行4.0.3的模拟器中启动Activity时,会发生以下异常:

    FATAL EXCEPTION: main
    android.view.InflateException: Couldn't resolve menu item onClick handler 
        onFeedbackMenu in class android.view.ContextThemeWrapper
    
    ...
    Caused by: java.lang.NoSuchMethodException: onFeedbackMenu 
        [interface com.actionbarsherlock.view.MenuItem]
    at java.lang.Class.getConstructorOrMethod(Class.java:460)
    

    我不明白导致异常的原因,因为我的Activity

    中定义了以下方法
    import com.actionbarsherlock.view.MenuItem;
    ...
    public void onFeedbackMenu( MenuItem menuItem ) { 
        Toast.makeText( this, "onFeedBack", Toast.LENGTH_LONG ).show();
    }
    

    我的XML菜单定义文件包含:

    <menu xmlns:android="http://schemas.android.com/apk/res/android" >
    ...
        <item
            android:id="@+id/menu_feedback"
            android:icon="@drawable/ic_action_share"
            android:showAsAction="ifRoom"
            android:title="@string/menu_feedback"
            android:onClick="onFeedbackMenu" />
    </menu>
    

    为了向后兼容,我正在使用ActionBarSherlock,并且当我在2.3.x上运行应用程序时也会得到一个非常类似的异常。

    这是堆栈跟踪的更完整版本

    FATAL EXCEPTION: main
    android.view.InflateException: Couldn't resolve menu item onClick handler 
        onFeedbackMenu in class android.view.ContextThemeWrapper
        at com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener.<init>(MenuInflater.java:204)
        at com.actionbarsherlock.view.MenuInflater$MenuState.setItem(MenuInflater.java:410)
        at com.actionbarsherlock.view.MenuInflater$MenuState.addItem(MenuInflater.java:445)
        at com.actionbarsherlock.view.MenuInflater.parseMenu(MenuInflater.java:175)
        at com.actionbarsherlock.view.MenuInflater.inflate(MenuInflater.java:97)
        ...
    Caused by: java.lang.NoSuchMethodException: onFeedbackMenu 
        [interface com.actionbarsherlock.view.MenuItem]
        at java.lang.Class.getConstructorOrMethod(Class.java:460)
        at java.lang.Class.getMethod(Class.java:915)
        at com.actionbarsherlock.view.MenuInflater$InflatedOnMenuItemClickListener.<init>(MenuInflater.java:202)
        ... 23 more
    

6 个答案:

答案 0 :(得分:73)

我找到了一个适合我的解决方案。 通常,布局中的onClick属性具有以下方法

public void methodname(View view) { 
    // actions
}

在菜单项(在本例中为Sherlock菜单)上,它应遵循以下签名:

public boolean methodname(MenuItem item) { 
    // actions
}

所以,您的问题是您的方法返回void而不是boolean

答案 1 :(得分:16)

就我而言,我的应用程序的AndroidManifest.xml(由默认的Eclipse助手启动)在android:theme="@style/AppTheme"块中包含<application>

调试问题原因时,结果是

mMethod = c.getMethod(methodName, PARAM_TYPES);
android.view.MenuInflater/InflatedOnMenuItemClickListener中的

被调用c不是我的Activity类,而是一个可疑的android.view.ContextThemeWrapper(当然不包含onClick处理程序)。

所以,我删除了android:theme,一切正常。

答案 2 :(得分:9)

虽然这有点过时,但这是异常的原因。当您在MenuInflater类中查看android API 15(4.0.3-4.0.4)的源代码时,您将看到此方法:

public InflatedOnMenuItemClickListener(Context context, String methodName) {
mContext = context;
Class<?> c = context.getClass();
try {
    mMethod = c.getMethod(methodName, PARAM_TYPES);
} catch (Exception e) {
    InflateException ex = new InflateException(
            "Couldn't resolve menu item onClick handler " + methodName +
            " in class " + c.getName());
    ex.initCause(e);
    throw ex;
}

这是例外情况,正如Junique已经指出的那样。然而,删除应用程序主题只是一种解决方法,没有真正的选择。正如我们所看到的,该方法试图在传递的上下文项的类上找到Callback方法。因此,不应在getMenuInflater()中调用onCreateOptionsMenu,而应调用new MenuInflater(this),以便this作为上下文传递,然后代码就可以运行。

如果你只使用这样的if语句,你仍然可以将getMenuInflater()用于其他api版本:

if (Build.VERSION.SDK_INT > 15)
        inflater = getMenuInflater();
    else
        inflater = new MenuInflater(this);

我实际上并不知道这个错误是否也发生在15岁以下的api版本中,所以我通常只使用保存版本。

答案 3 :(得分:0)

我发现ActionBar菜单项及其onClick事件存在同样的问题。我发现我正在开发的工作站耗尽内存并需要重新启动。 Android VM现在能够解析引用的方法名称。

答案 4 :(得分:0)

您的方法必须接受here中的MenuItem作为其唯一参数。

    public void onMenuItemClickMethod(MenuItem menuItem){
        // Do stuff here
    }

答案 5 :(得分:-1)

@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
    getMenuInflater().inflate(R.menu.activity_main, menu);

    MenuItem item = menu.findItem(R.id.menu_open);

    if (item == null)
        return true;

    item.setOnMenuItemClickListener
    (
        new MenuItem.OnMenuItemClickListener () 
        { 
            public boolean onMenuItemClick(MenuItem item) 
            { return (showDirectory(item)); }
        } 
    ); 

    return true;
}


public boolean showDirectory (MenuItem item)
{
    CheckBox checkBox = (CheckBox) findViewById (R.id.checkBox1);
    checkBox.setChecked(true);
}