36

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

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

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

我从不使用的原因onClick

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

我希望我已经说服你永远不要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)

我不明白是什么导致了异常,因为我的活动中定义了以下方法

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
4

7 回答 7

76

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

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

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

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

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

于 2012-09-18T22:41:05.517 回答
16

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

调试问题原因的时候,原来是行

mMethod = c.getMethod(methodName, PARAM_TYPES);

in不是我的android.view.MenuInflater/InflatedOnMenuItemClickListener班级而是可疑的(当然不包含 onClick 处理程序)。cActivityandroid.view.ContextThemeWrapper

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

于 2013-01-14T01:42:14.990 回答
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 已经指出的那样,这是例外情况。但是,删除应用程序主题只是一种解决方法,并没有真正的选择。正如我们所见,该方法试图在传递的上下文项的类上找到回调方法。因此getMenuInflater()onCreateOptionsMenu您应该调用而不是调用new MenuInflater(this),以便将this其作为上下文传递,然后代码将起作用。

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

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

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

于 2014-07-01T18:43:59.427 回答
1

就我而言,问题在于我的菜单 XML 和活动中都有 。我的实际上是错误的(因为它指向不存在的方法)但我一开始并没有注意到这一点,因为我在 Android 2.x 下进行测试,不支持和忽略。但是,一旦我在 4.x 上进行测试,我就开始收到此错误。onClickonCreateOptionsMenuonClickonClick

onClick所以基本上,如果您打算在 Android 2.x 下部署,请不要使用。它会默默地忽略您的onClick值,直到您尝试在 3.0+ 上运行。

于 2012-09-20T22:07:59.370 回答
0

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

于 2012-07-01T07:10:42.357 回答
0

你的方法必须接受一个 MenuItem 作为它的唯一参数

    public void onMenuItemClickMethod(MenuItem menuItem){
        // Do stuff here
    }
于 2018-10-10T08:21:35.987 回答
-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);
}
于 2012-07-01T18:08:01.883 回答