【问题标题】:InflateException: Couldn't resolve menu item onClick handlerInflateException:无法解析菜单项 onClick 处理程序
【发布时间】:2012-06-30 01:02:16
【问题描述】:

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

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

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

我从不使用onClick的原因是

  1. onClick XML 属性的值很容易出错,从而导致运行时错误
  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)

我不明白是什么导致了异常,因为在我的 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

【问题讨论】:

  • 我遇到了同样的问题,似乎与将自定义主题应用于 ActionBarSherlock 有关,但不确定...您使用的是自定义主题吗?
  • 是的,我正在使用自定义主题。
  • 是的,这发生在我真正的 4.0.3 设备上,但不是在 4.1 模拟器中。我只能假设这是 Android 中的一个错误,此后已被修复。我没有使用 ActionBarSherlock。
  • 下面有一些很好的答案。接受答案将是一件好事!

标签: android android-actionbar actionbarsherlock


【解决方案1】:

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

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

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

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

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

【讨论】:

    【解决方案2】:

    在我的例子中,我的应用程序的 AndroidManifest.xml(由默认 Eclipse 助手启动)在 &lt;application&gt; 块中包含 android:theme="@style/AppTheme"

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

    mMethod = c.getMethod(methodName, PARAM_TYPES);
    

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

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

    【讨论】:

    • 这个很有趣,因为看起来这是我的问题的原因。但是,任何需要(或想要)主题集的人最终都会遇到这个问题(据我所知,在 API 14/15 上,而不是 API 16+)。因此,我的解决方案是放弃 onClick 分配,只添加对 onOptionsItemSelected() 方法的调用。
    【解决方案3】:

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

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

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

    其实我不知道这个bug是否也发生在15以下的api版本中,所以我一般只使用save版本。

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

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

        【讨论】:

        • 更新,当我重新启动时,我没有意识到出现的Android VM是2.3.3。但是,当我特别选择 Android VM 为 4.0.3 时,我继续收到 onClick 的错误。
        • @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.activity_main, menu); MenuItem item = menu.findItem(R.id.menu_open); if (item == null) 返回真; item.setOnMenuItemClickListener ( new MenuItem.OnMenuItemClickListener () { public boolean onMenuItemClick(MenuItem item) { return (showDirectory(item)); } } );返回真; }
        【解决方案6】:

        根据here,您的方法必须接受一个 MenuItem 作为其唯一参数。

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

        【讨论】:

          【解决方案7】:
          @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);
          }
          

          【讨论】:

          • 基于此线程 ..stackoverflow.com/questions/6150080/… .. 建议程序员使用 menu.findItem () vs findItemById() 更新菜单。为了实现这一点,菜单选项在 onCreateOptionsMenu 或 onPrepareOptionsMenu .. 讨论这里.. developer.android.com/guide/topics/ui/menus.html
          • 我认为 XML 文件发生的另一件事是 onClick 字段无法解析为匹配正确标准的方法......它应该是...... public void [eventName ](MenuItem 项){} 或公共布尔值 [eventName](MenuItem 项){}。虽然似乎都不起作用。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-17
          • 2011-09-06
          • 2018-07-24
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多